diff options
author | Jeremy Allison <jra@samba.org> | 2002-02-01 22:15:18 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2002-02-01 22:15:18 +0000 |
commit | 8d63a817bb04da3c7cc43e342a9034f5f23c5041 (patch) | |
tree | de549371c7728978ab045eab1a658b29007cc9ad /source/smbd | |
parent | f98c14e8d6d8f1def0edcd02e1dfe66bab8a2ab6 (diff) | |
download | samba-8d63a817bb04da3c7cc43e342a9034f5f23c5041.tar.gz samba-8d63a817bb04da3c7cc43e342a9034f5f23c5041.tar.xz samba-8d63a817bb04da3c7cc43e342a9034f5f23c5041.zip |
Move over to RELEASE branch.
Jeremy.
Diffstat (limited to 'source/smbd')
43 files changed, 6007 insertions, 4624 deletions
diff --git a/source/smbd/.cvsignore b/source/smbd/.cvsignore index e69de29bb2d..5f2a5c4cf75 100644 --- a/source/smbd/.cvsignore +++ b/source/smbd/.cvsignore @@ -0,0 +1,2 @@ +*.po +*.po32 diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c index 6f633c0bc20..0d2a99b3f07 100644 --- a/source/smbd/blocking.c +++ b/source/smbd/blocking.c @@ -20,7 +20,7 @@ */ #include "includes.h" -extern int DEBUGLEVEL; + extern char *OutBuffer; /**************************************************************************** @@ -46,8 +46,8 @@ static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_qu static void free_blocking_lock_record(blocking_lock_record *blr) { - free(blr->inbuf); - free((char *)blr); + SAFE_FREE(blr->inbuf); + SAFE_FREE(blr); } /**************************************************************************** @@ -103,7 +103,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int if((blr->inbuf = (char *)malloc(length)) == NULL) { DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" )); - free((char *)blr); + SAFE_FREE(blr); return False; } @@ -134,7 +134,7 @@ static void send_blocking_reply(char *outbuf, int outsize) smb_setlen(outbuf,outsize - 4); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_blocking_reply: send_smb failed.\n"); + exit_server("send_blocking_reply: send_smb failed."); } /**************************************************************************** @@ -170,15 +170,15 @@ static void reply_lockingX_success(blocking_lock_record *blr) Return a generic lock fail error blocking call. *****************************************************************************/ -static void generic_blocking_lock_error(blocking_lock_record *blr, int eclass, int32 ecode) +static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status) { char *outbuf = OutBuffer; char *inbuf = blr->inbuf; construct_reply_common(inbuf, outbuf); - ERROR(eclass,ecode); + ERROR_NT(status); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("generic_blocking_lock_error: send_smb failed.\n"); + exit_server("generic_blocking_lock_error: send_smb failed."); } /**************************************************************************** @@ -186,72 +186,68 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, int eclass, i obtained first. *****************************************************************************/ -static void reply_lockingX_error(blocking_lock_record *blr, int eclass, int32 ecode) +static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status) { - char *inbuf = blr->inbuf; - files_struct *fsp = blr->fsp; - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0; - uint16 lock_pid; - unsigned char locktype = CVAL(inbuf,smb_vwv3); - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); - char *data; - int i; - - data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks); - - /* - * Data now points at the beginning of the list - * of smb_lkrng structs. - */ - - /* - * Ensure we don't do a remove on the lock that just failed, - * as under POSIX rules, if we have a lock already there, we - * will delete it (and we shouldn't) ..... - */ - - for(i = blr->lock_num - 1; i >= 0; i--) { - int dummy1; - uint32 dummy2; - BOOL err; - - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); - - /* - * We know err cannot be set as if it was the lock - * request would never have been queued. JRA. - */ - - do_unlock(fsp,conn,lock_pid,count,offset,&dummy1,&dummy2); - } - - generic_blocking_lock_error(blr, eclass, ecode); + char *inbuf = blr->inbuf; + files_struct *fsp = blr->fsp; + connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); + uint16 num_ulocks = SVAL(inbuf,smb_vwv6); + SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0; + uint16 lock_pid; + unsigned char locktype = CVAL(inbuf,smb_vwv3); + BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); + char *data; + int i; + + data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks); + + /* + * Data now points at the beginning of the list + * of smb_lkrng structs. + */ + + /* + * Ensure we don't do a remove on the lock that just failed, + * as under POSIX rules, if we have a lock already there, we + * will delete it (and we shouldn't) ..... + */ + + for(i = blr->lock_num - 1; i >= 0; i--) { + BOOL err; + + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); + + /* + * We know err cannot be set as if it was the lock + * request would never have been queued. JRA. + */ + + do_unlock(fsp,conn,lock_pid,count,offset); + } + + generic_blocking_lock_error(blr, status); } /**************************************************************************** Return a lock fail error. *****************************************************************************/ -static void blocking_lock_reply_error(blocking_lock_record *blr, int eclass, int32 ecode) +static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status) { - switch(blr->com_type) { - case SMBlock: - generic_blocking_lock_error(blr, eclass, ecode); - break; - case SMBlockread: - generic_blocking_lock_error(blr, eclass, ecode); - break; - case SMBlockingX: - reply_lockingX_error(blr, eclass, ecode); - break; - default: - DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); - exit_server("PANIC - unknown type on blocking lock queue"); - } + switch(blr->com_type) { + case SMBlock: + case SMBlockread: + generic_blocking_lock_error(blr, status); + break; + case SMBlockingX: + reply_lockingX_error(blr, status); + break; + default: + DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); + exit_server("PANIC - unknown type on blocking lock queue"); + } } /**************************************************************************** @@ -261,65 +257,68 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, int eclass, int static BOOL process_lockread(blocking_lock_record *blr) { - char *outbuf = OutBuffer; - char *inbuf = blr->inbuf; - ssize_t nread = -1; - char *data; - int outsize = 0; - SMB_OFF_T startpos; - size_t numtoread; - int eclass; - uint32 ecode; - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - files_struct *fsp = blr->fsp; - - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; + char *outbuf = OutBuffer; + char *inbuf = blr->inbuf; + ssize_t nread = -1; + char *data, *p; + int outsize = 0; + SMB_OFF_T startpos; + size_t numtoread; + NTSTATUS status; + connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); + files_struct *fsp = blr->fsp; + + numtoread = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); + + numtoread = MIN(BUFFER_SIZE-outsize,numtoread); + data = smb_buf(outbuf) + 3; - if(!do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, READ_LOCK, &eclass, &ecode)) { - if((errno != EACCES) && (errno != EAGAIN)) { - /* - * We have other than a "can't get lock" POSIX - * error. Send an error. - * Return True so we get dequeued. - */ - - generic_blocking_lock_error(blr, eclass, ecode); - return True; - } - - /* - * Still waiting for lock.... - */ - - DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n", - fsp->fsp_name)); - return False; - } - - nread = read_file(fsp,data,startpos,numtoread); - - if (nread < 0) { - generic_blocking_lock_error(blr,ERRDOS,ERRnoaccess); - return True; - } - - construct_reply_common(inbuf, outbuf); - outsize = set_message(outbuf,5,3,True); - - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SSVAL(smb_buf(outbuf),1,nread); - - DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n", - fsp->fsp_name, fsp->fnum, (int)numtoread, (int)nread ) ); - - send_blocking_reply(outbuf,outsize); - return True; + status = do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, + (SMB_BIG_UINT)startpos, READ_LOCK); + if (NT_STATUS_V(status)) { + if ((errno != EACCES) && (errno != EAGAIN)) { + /* + * We have other than a "can't get lock" POSIX + * error. Send an error. + * Return True so we get dequeued. + */ + generic_blocking_lock_error(blr, status); + return True; + } + + /* + * Still waiting for lock.... + */ + + DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n", + fsp->fsp_name)); + return False; + } + + nread = read_file(fsp,data,startpos,numtoread); + + if (nread < 0) { + generic_blocking_lock_error(blr,NT_STATUS_ACCESS_DENIED); + return True; + } + + construct_reply_common(inbuf, outbuf); + outsize = set_message(outbuf,5,0,True); + + outsize += nread; + SSVAL(outbuf,smb_vwv0,nread); + SSVAL(outbuf,smb_vwv5,nread+3); + p = smb_buf(outbuf); + *p++ = 1; + SSVAL(p,0,nread); p += 2; + set_message_end(outbuf, p+nread); + + DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n", + fsp->fsp_name, fsp->fnum, (int)numtoread, (int)nread ) ); + + send_blocking_reply(outbuf,outsize); + return True; } /**************************************************************************** @@ -329,52 +328,50 @@ static BOOL process_lockread(blocking_lock_record *blr) static BOOL process_lock(blocking_lock_record *blr) { - char *outbuf = OutBuffer; - char *inbuf = blr->inbuf; - int outsize; - SMB_OFF_T count = 0, offset = 0; - int eclass; - uint32 ecode; - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - files_struct *fsp = blr->fsp; - - count = IVAL(inbuf,smb_vwv1); - offset = IVAL(inbuf,smb_vwv3); - - errno = 0; - if (!do_lock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)count, (SMB_BIG_UINT)offset, WRITE_LOCK, &eclass, &ecode)) { - if((errno != EACCES) && (errno != EAGAIN)) { - - /* - * We have other than a "can't get lock" POSIX - * error. Send an error. - * Return True so we get dequeued. - */ - - blocking_lock_reply_error(blr, eclass, ecode); - return True; - } - - /* - * Still can't get the lock - keep waiting. - */ - - DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n", - fsp->fsp_name)); - return False; - } - - /* - * Success - we got the lock. - */ - - DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n", - fsp->fsp_name, fsp->fnum, (double)offset, (double)count)); - - construct_reply_common(inbuf, outbuf); - outsize = set_message(outbuf,0,0,True); - send_blocking_reply(outbuf,outsize); - return True; + char *outbuf = OutBuffer; + char *inbuf = blr->inbuf; + int outsize; + SMB_OFF_T count = 0, offset = 0; + NTSTATUS status; + connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); + files_struct *fsp = blr->fsp; + + count = IVAL(inbuf,smb_vwv1); + offset = IVAL(inbuf,smb_vwv3); + + errno = 0; + status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)count, + (SMB_BIG_UINT)offset, WRITE_LOCK); + if (NT_STATUS_IS_ERR(status)) { + if((errno != EACCES) && (errno != EAGAIN)) { + /* + * We have other than a "can't get lock" POSIX + * error. Send an error. + * Return True so we get dequeued. + */ + + blocking_lock_reply_error(blr, status); + return True; + } + /* + * Still can't get the lock - keep waiting. + */ + DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n", + fsp->fsp_name)); + return False; + } + + /* + * Success - we got the lock. + */ + + DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n", + fsp->fsp_name, fsp->fnum, (double)offset, (double)count)); + + construct_reply_common(inbuf, outbuf); + outsize = set_message(outbuf,0,0,True); + send_blocking_reply(outbuf,outsize); + return True; } /**************************************************************************** @@ -384,75 +381,72 @@ static BOOL process_lock(blocking_lock_record *blr) static BOOL process_lockingX(blocking_lock_record *blr) { - char *inbuf = blr->inbuf; - unsigned char locktype = CVAL(inbuf,smb_vwv3); - files_struct *fsp = blr->fsp; - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0; - uint16 lock_pid; - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); - char *data; - int eclass=0; - uint32 ecode=0; - - data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks); - - /* - * Data now points at the beginning of the list - * of smb_lkrng structs. - */ - - for(; blr->lock_num < num_locks; blr->lock_num++) { - BOOL err; - - lock_pid = get_lock_pid( data, blr->lock_num, large_file_format); - count = get_lock_count( data, blr->lock_num, large_file_format); - offset = get_lock_offset( data, blr->lock_num, large_file_format, &err); - - /* - * We know err cannot be set as if it was the lock - * request would never have been queued. JRA. - */ - errno = 0; - if(!do_lock(fsp,conn,lock_pid,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK), - &eclass, &ecode)) - break; - } - - if(blr->lock_num == num_locks) { - - /* - * Success - we got all the locks. - */ - - DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n", - fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) ); - - reply_lockingX_success(blr); - return True; - - } else if((errno != EACCES) && (errno != EAGAIN)) { - - /* - * We have other than a "can't get lock" POSIX - * error. Free any locks we had and return an error. - * Return True so we get dequeued. - */ - - blocking_lock_reply_error(blr, eclass, ecode); - return True; - } - - /* - * Still can't get all the locks - keep waiting. - */ - - DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \ -Waiting....\n", blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum)); - - return False; + char *inbuf = blr->inbuf; + unsigned char locktype = CVAL(inbuf,smb_vwv3); + files_struct *fsp = blr->fsp; + connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); + uint16 num_ulocks = SVAL(inbuf,smb_vwv6); + uint16 num_locks = SVAL(inbuf,smb_vwv7); + SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0; + uint16 lock_pid; + BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); + char *data; + NTSTATUS status = NT_STATUS_OK; + + data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks); + + /* + * Data now points at the beginning of the list + * of smb_lkrng structs. + */ + + for(; blr->lock_num < num_locks; blr->lock_num++) { + BOOL err; + + lock_pid = get_lock_pid( data, blr->lock_num, large_file_format); + count = get_lock_count( data, blr->lock_num, large_file_format); + offset = get_lock_offset( data, blr->lock_num, large_file_format, &err); + + /* + * We know err cannot be set as if it was the lock + * request would never have been queued. JRA. + */ + errno = 0; + status = do_lock(fsp,conn,lock_pid,count,offset, + ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); + if (NT_STATUS_IS_ERR(status)) break; + } + + if(blr->lock_num == num_locks) { + /* + * Success - we got all the locks. + */ + + DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n", + fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) ); + + reply_lockingX_success(blr); + return True; + } else if ((errno != EACCES) && (errno != EAGAIN)) { + /* + * We have other than a "can't get lock" POSIX + * error. Free any locks we had and return an error. + * Return True so we get dequeued. + */ + + blocking_lock_reply_error(blr, status); + return True; + } + + /* + * Still can't get all the locks - keep waiting. + */ + + DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \ +Waiting....\n", + blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum)); + + return False; } /**************************************************************************** @@ -517,7 +511,7 @@ void remove_pending_lock_requests_by_mid(int mid) DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); - blocking_lock_reply_error(blr,0,NT_STATUS_CANCELLED); + blocking_lock_reply_error(blr,NT_STATUS_CANCELLED); free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); continue; @@ -582,33 +576,33 @@ void process_blocking_lock_queue(time_t t) DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n", fsp->fnum, fsp->fsp_name )); - blocking_lock_reply_error(blr,ERRSRV,ERRaccess); + blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED); free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); continue; } - if(!become_user(conn,vuid)) { + if(!change_to_user(conn,vuid)) { DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n", vuid )); /* * Remove the entry and return an error to the client. */ - blocking_lock_reply_error(blr,ERRSRV,ERRaccess); + blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED); free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); continue; } - if(!become_service(conn,True)) { + if(!set_current_service(conn,True)) { DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) )); /* * Remove the entry and return an error to the client. */ - blocking_lock_reply_error(blr,ERRSRV,ERRaccess); + blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED); free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); - unbecome_user(); + change_to_root_user(); continue; } @@ -621,11 +615,11 @@ void process_blocking_lock_queue(time_t t) if(blocking_lock_record_process(blr)) { free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); - unbecome_user(); + change_to_root_user(); continue; } - unbecome_user(); + change_to_root_user(); /* * Move to the next in the list. diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c index 245c1d1ea9b..bc91d776936 100644 --- a/source/smbd/chgpasswd.c +++ b/source/smbd/chgpasswd.c @@ -49,7 +49,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern struct passdb_ops pdb_ops; #if ALLOW_CHANGE_PASSWORD @@ -309,6 +308,12 @@ static int talktochild(int master, char *seq) pwd_sub(issue); } + if (!strequal(issue, ".")) { + /* we have one final issue to send */ + fstrcpy(expected, "."); + if (!expect(master, issue, expected)) + return False; + } return (count > 0); } @@ -754,6 +759,7 @@ BOOL check_oem_password(char *user, if (ret == False) { DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n")); + pdb_free_sam(sampass); return False; } diff --git a/source/smbd/close.c b/source/smbd/close.c index 7c0672efe0d..ca030ed1404 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - /**************************************************************************** run a file if it is a magic script ****************************************************************************/ @@ -102,10 +100,7 @@ static int close_filestruct(files_struct *fsp) fsp->stat_open = False; conn->num_files_open--; - if(fsp->wbmpx_ptr) { - free((char *)fsp->wbmpx_ptr); - fsp->wbmpx_ptr = NULL; - } + SAFE_FREE(fsp->wbmpx_ptr); return ret; } @@ -172,21 +167,21 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) * reference to a file. */ - if (normal_close && delete_on_close) { - DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", - fsp->fsp_name)); + if (normal_close && delete_on_close) { + DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", + fsp->fsp_name)); if(fsp->conn->vfs_ops.unlink(conn,dos_to_unix(fsp->fsp_name, False)) != 0) { - /* - * This call can potentially fail as another smbd may have - * had the file open with delete on close set and deleted - * it when its last reference to this file went away. Hence - * we log this but not at debug level zero. - */ - - DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \ + /* + * This call can potentially fail as another smbd may have + * had the file open with delete on close set and deleted + * it when its last reference to this file went away. Hence + * we log this but not at debug level zero. + */ + + DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \ with error %s\n", fsp->fsp_name, strerror(errno) )); - } - } + } + } unlock_share_entry_fsp(fsp); @@ -202,14 +197,22 @@ with error %s\n", fsp->fsp_name, strerror(errno) )); check_magic(fsp,conn); } + /* + * Ensure pending modtime is set after close. + */ + + if(fsp->pending_modtime) { + int saved_errno = errno; + set_filetime(conn, fsp->fsp_name, fsp->pending_modtime); + errno = saved_errno; + } DEBUG(2,("%s closed file %s (numopen=%d) %s\n", conn->user,fsp->fsp_name, conn->num_files_open, err ? strerror(err) : "")); - if (fsp->fsp_name) { + if (fsp->fsp_name) string_free(&fsp->fsp_name); - } file_free(fsp); @@ -244,7 +247,7 @@ static int close_directory(files_struct *fsp, BOOL normal_close) if(ok) remove_pending_change_notify_requests_by_filename(fsp); - } + } /* * Do the code common to files and directories. diff --git a/source/smbd/conn.c b/source/smbd/conn.c index 725ab22dc44..7e8a8383213 100644 --- a/source/smbd/conn.c +++ b/source/smbd/conn.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - /* set these to define the limits of the server. NOTE These are on a per-client basis. Thus any one machine can't connect to more than MAX_CONNECTIONS services, but any number of machines may connect at @@ -177,7 +175,7 @@ void conn_free(connection_struct *conn) DLIST_REMOVE(Connections, conn); if (conn->ngroups && conn->groups) { - free(conn->groups); + SAFE_FREE(conn->groups); conn->groups = NULL; conn->ngroups = 0; } @@ -196,7 +194,7 @@ void conn_free(connection_struct *conn) num_open--; ZERO_STRUCTP(conn); - free(conn); + SAFE_FREE(conn); } diff --git a/source/smbd/connection.c b/source/smbd/connection.c index 9e074a8e809..3ca4021abe4 100644 --- a/source/smbd/connection.c +++ b/source/smbd/connection.c @@ -25,8 +25,6 @@ extern fstring remote_machine; static TDB_CONTEXT *tdb; -extern int DEBUGLEVEL; - /**************************************************************************** Return the connection tdb context (used for message send all). ****************************************************************************/ @@ -40,7 +38,7 @@ TDB_CONTEXT *conn_tdb_ctx(void) Delete a connection record. ****************************************************************************/ -BOOL yield_connection(connection_struct *conn,char *name,int max_connections) +BOOL yield_connection(connection_struct *conn,char *name) { struct connections_key key; TDB_DATA kbuf; @@ -59,8 +57,9 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections) kbuf.dsize = sizeof(key); if (tdb_delete(tdb, kbuf) != 0) { - DEBUG(0,("yield_connection: tdb_delete for name %s failed with error %s.\n", - name, tdb_errorstr(tdb) )); + int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0; + DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n", + name, tdb_errorstr(tdb) )); return (False); } @@ -88,7 +87,7 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u memcpy(&crec, dbuf.dptr, sizeof(crec)); - if (crec.cnum == -1) + if (crec.cnum == -1) return 0; /* If the pid was not found delete the entry from connections.tdb */ diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c index 64c6182cd8d..034e1a093d3 100644 --- a/source/smbd/dfree.c +++ b/source/smbd/dfree.c @@ -21,9 +21,6 @@ #include "includes.h" - -extern int DEBUGLEVEL; - /**************************************************************************** normalise for DOS usage ****************************************************************************/ diff --git a/source/smbd/dir.c b/source/smbd/dir.c index fa9cbdc4a2a..789ff919eea 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - /* This module implements directory related functions for Samba. */ @@ -246,10 +244,9 @@ static void dptr_close_internal(dptr_struct *dptr) } /* Lanman 2 specific code */ - if (dptr->wcard) - free(dptr->wcard); + SAFE_FREE(dptr->wcard); string_set(&dptr->path,""); - free((char *)dptr); + SAFE_FREE(dptr); } /**************************************************************************** @@ -438,7 +435,7 @@ int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect if(dptr->dnum == -1 || dptr->dnum > 254) { DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum)); - free((char *)dptr); + SAFE_FREE(dptr); return -1; } } @@ -467,7 +464,7 @@ int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect if(dptr->dnum == -1 || dptr->dnum < 255) { DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum)); - free((char *)dptr); + SAFE_FREE(dptr); return -1; } } @@ -669,12 +666,47 @@ check to see if a user can read a file. This is only approximate, it is used as part of the "hide unreadable" option. Don't use it for anything security sensitive ********************************************************************/ + static BOOL user_can_read_file(connection_struct *conn, char *name) { + extern struct current_user current_user; SMB_STRUCT_STAT ste; + SEC_DESC *psd = NULL; + size_t sd_size; + files_struct *fsp; + int smb_action; + NTSTATUS status; + uint32 access_granted; + + ZERO_STRUCT(ste); /* if we can't stat it does not show it */ - if (vfs_stat(conn, name, &ste) != 0) return False; + if (vfs_stat(conn, name, &ste) != 0) + return False; + + /* Pseudo-open the file (note - no fd's created). */ + + if(S_ISDIR(ste.st_mode)) + fsp = open_directory(conn, name, &ste, SET_DENY_MODE(DENY_NONE), FILE_OPEN, + unix_mode(conn,aRONLY|aDIR, name), &smb_action); + else + fsp = open_file_stat(conn,name,&ste,DOS_OPEN_RDONLY,&smb_action); + if (!fsp) + return False; + + /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ + sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + close_file(fsp, True); + + /* No access if SD get failed. */ + if (!sd_size) + return False; + + return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA, + &access_granted, &status); + +#if 0 + /* Old - crappy check :-). JRA */ if (ste.st_uid == conn->uid) { return (ste.st_mode & S_IRUSR) == S_IRUSR; @@ -691,6 +723,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) } return (ste.st_mode & S_IROTH) == S_IROTH; +#endif } /******************************************************************* @@ -733,7 +766,7 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { ret = user_can_read_file(conn, entry); - free(entry); + SAFE_FREE(entry); } if (!ret) continue; } @@ -768,8 +801,8 @@ void CloseDir(void *p) { Dir *dirp = (Dir *)p; if (!dirp) return; - if (dirp->data) free(dirp->data); - free(dirp); + SAFE_FREE(dirp->data); + SAFE_FREE(dirp); } /******************************************************************* @@ -878,7 +911,7 @@ void DirCacheAdd( char *path, char *name, char *dname, int snum ) /* Free excess cache entries. */ while( DIRCACHESIZE < dir_cache->count ) - free( ubi_dlRemTail( dir_cache ) ); + safe_free( ubi_dlRemTail( dir_cache ) ); } @@ -930,7 +963,7 @@ void DirCacheFlush(int snum) NULL != entry; ) { next = ubi_dlNext( entry ); if( entry->snum == snum ) - free( ubi_dlRemThis( dir_cache, entry ) ); + safe_free( ubi_dlRemThis( dir_cache, entry ) ); entry = (dir_cache_entry *)next; } } diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index 9ec1fa26069..d7b40198771 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - /**************************************************************************** change a dos mode to a unix mode base permission for files: diff --git a/source/smbd/error.c b/source/smbd/error.c index 164f4e42a56..0a63d520ee6 100644 --- a/source/smbd/error.c +++ b/source/smbd/error.c @@ -21,50 +21,39 @@ #include "includes.h" -extern int DEBUGLEVEL; -extern uint32 global_client_caps; - /* these can be set by some functions to override the error codes */ int unix_ERR_class=SMB_SUCCESS; int unix_ERR_code=0; -struct { - int unixerror; - int smbclass; - int smbcode; -} unix_smb_errmap[] = { - {EPERM,ERRDOS,ERRnoaccess}, - {EACCES,ERRDOS,ERRnoaccess}, - {ENOENT,ERRDOS,ERRbadfile}, - {ENOTDIR,ERRDOS,ERRbadpath}, - {EIO,ERRHRD,ERRgeneral}, - {EBADF,ERRDOS,ERRbadfid}, - {EINVAL,ERRSRV,ERRsrverror}, - {EEXIST,ERRDOS,ERRfilexists}, - {ENFILE,ERRDOS,ERRnofids}, - {EMFILE,ERRDOS,ERRnofids}, - {ENOSPC,ERRHRD,ERRdiskfull}, -#ifdef EDQUOT - {EDQUOT,ERRHRD,ERRdiskfull}, -#endif -#ifdef ENOTEMPTY - {ENOTEMPTY,ERRDOS,ERRnoaccess}, -#endif -#ifdef EXDEV - {EXDEV,ERRDOS,ERRdiffdevice}, -#endif - {EROFS,ERRHRD,ERRnowrite}, - {0,0,0} -}; +/* From lib/error.c */ +extern struct unix_error_map unix_dos_nt_errmap[]; + +/**************************************************************************** + Create an error packet from a cached error. +****************************************************************************/ + +int cached_error_packet(char *outbuf,files_struct *fsp,int line,const char *file) +{ + write_bmpx_struct *wbmpx = fsp->wbmpx_ptr; + + int32 eclass = wbmpx->wr_errclass; + int32 err = wbmpx->wr_error; + + /* We can now delete the auxiliary struct */ + SAFE_FREE(wbmpx); + return error_packet(outbuf,NT_STATUS_OK,eclass,err,line,file); +} /**************************************************************************** Create an error packet from errno. ****************************************************************************/ -int unix_error_packet(char *outbuf,int def_class,uint32 def_code,int line, const char *file) +int unix_error_packet(char *outbuf,int def_class,uint32 def_code, + int line, const char *file) { int eclass=def_class; int ecode=def_code; + NTSTATUS ntstatus = NT_STATUS_OK; int i=0; if (unix_ERR_class != SMB_SUCCESS) { @@ -73,44 +62,62 @@ int unix_error_packet(char *outbuf,int def_class,uint32 def_code,int line, const unix_ERR_class = SMB_SUCCESS; unix_ERR_code = 0; } else { - while (unix_smb_errmap[i].smbclass != 0) { - if (unix_smb_errmap[i].unixerror == errno) { - eclass = unix_smb_errmap[i].smbclass; - ecode = unix_smb_errmap[i].smbcode; + while (unix_dos_nt_errmap[i].dos_class != 0) { + if (unix_dos_nt_errmap[i].unix_error == errno) { + eclass = unix_dos_nt_errmap[i].dos_class; + ecode = unix_dos_nt_errmap[i].dos_code; + ntstatus = unix_dos_nt_errmap[i].nt_error; break; } i++; } } - return(error_packet(outbuf,0,eclass,ecode,line,file)); + return error_packet(outbuf,ntstatus,eclass,ecode,line,file); } + /**************************************************************************** Create an error packet. Normally called using the ERROR() macro. ****************************************************************************/ -int error_packet(char *outbuf,uint32 nt_err, int error_class,uint32 error_code,int line, const char *file) +int error_packet(char *outbuf,NTSTATUS ntstatus, + uint8 eclass,uint32 ecode,int line, const char *file) { int outsize = set_message(outbuf,0,0,True); - int cmd = CVAL(outbuf,smb_com); + extern uint32 global_client_caps; if (errno != 0) DEBUG(3,("error string = %s\n",strerror(errno))); - if ((global_client_caps & CAP_STATUS32) && (nt_err != 0)) { - SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); - SIVAL(outbuf,smb_rcls,nt_err); - - DEBUG( 3, ( "32 bit error packet at %s(%d) cmd=%d (%s) eclass=%08x [%s]\n", - file, line, cmd, smb_fn_name(cmd), nt_err, smb_errstr(outbuf) ) ); + if (global_client_caps & CAP_STATUS32) { + if (NT_STATUS_V(ntstatus) == 0 && eclass) { + ntstatus = dos_to_ntstatus(eclass, ecode); + } + SIVAL(outbuf,smb_rcls,NT_STATUS_V(ntstatus)); + SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES); + DEBUG(3,("error packet at %s(%d) cmd=%d (%s) %s\n", + file, line, + (int)CVAL(outbuf,smb_com), + smb_fn_name(CVAL(outbuf,smb_com)), + get_nt_error_msg(ntstatus))); + return outsize; + } - } else { - CVAL(outbuf,smb_rcls) = error_class; - SSVAL(outbuf,smb_err,error_code); - DEBUG( 3, ( "error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n", - file, line, cmd, smb_fn_name(cmd), error_class, error_code ) ); + if (eclass == 0 && NT_STATUS_V(ntstatus)) { + ntstatus_to_dos(ntstatus, &eclass, &ecode); } - - return(outsize); + + SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2)&~FLAGS2_32_BIT_ERROR_CODES); + SSVAL(outbuf,smb_rcls,eclass); + SSVAL(outbuf,smb_err,ecode); + + DEBUG(3,("error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d\n", + file, line, + (int)CVAL(outbuf,smb_com), + smb_fn_name(CVAL(outbuf,smb_com)), + eclass, + ecode)); + + return outsize; } diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index c79f0aa89e0..ba60690383b 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - static BOOL setup_write_cache(files_struct *, SMB_OFF_T); /**************************************************************************** @@ -93,34 +91,50 @@ read from a file ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) { - ssize_t ret=0,readret; + ssize_t ret=0,readret; - /* you can't read from print files */ - if (fsp->print_file) { - return -1; - } + /* you can't read from print files */ + if (fsp->print_file) + return -1; - /* - * Serve from write cache if we can. - */ - if(read_from_write_cache(fsp, data, pos, n)) - return n; + /* + * Serve from write cache if we can. + */ - flush_write_cache(fsp, READ_FLUSH); + if(read_from_write_cache(fsp, data, pos, n)) + return n; - if (seek_file(fsp,pos) == -1) { - DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos)); - return(ret); - } + flush_write_cache(fsp, READ_FLUSH); + + if (seek_file(fsp,pos) == -1) { + DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos)); + return(ret); + } - if (n > 0) { - readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n); - if (readret == -1) - return -1; - if (readret > 0) ret += readret; - } + if (n > 0) { +#ifdef DMF_FIX + int numretries = 3; +tryagain: + readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n); + if (readret == -1) { + if ((errno == EAGAIN) && numretries) { + DEBUG(3,("read_file EAGAIN retry in 10 seconds\n")); + (void)sleep(10); + --numretries; + goto tryagain; + } + return -1; + } +#else /* NO DMF fix. */ + readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n); + if (readret == -1) + return -1; +#endif + if (readret > 0) + ret += readret; + } - return(ret); + return(ret); } /* how many write cache buffers have been allocated */ @@ -163,6 +177,7 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n) if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) { int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); + fsp->size = st.st_size; if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) { file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st); } @@ -223,11 +238,14 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", if(!wcp) { DO_PROFILE_INC(writecache_direct_writes); - return real_write_file(fsp, data, pos, n); + total_written = real_write_file(fsp, data, pos, n); + if ((total_written != -1) && (pos + total_written > fsp->size)) + fsp->size = pos + total_written; + return total_written; } - DEBUG(9,("write_file(fd=%d pos=%d size=%d) wofs=%d wsize=%d\n", - fsp->fd, (int)pos, (int)n, (int)wcp->offset, (int)wcp->data_size)); + DEBUG(9,("write_file(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", + fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); /* * If we have active cache and it isn't contiguous then we flush. @@ -256,6 +274,13 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", wcp->data_size = pos + data_used - wcp->offset; /* + * Update the file size if changed. + */ + + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + + /* * If we used all the data then * return here. */ @@ -298,6 +323,13 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", wcp->data_size = pos + n - wcp->offset; /* + * Update the file size if changed. + */ + + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + + /* * We don't need to move the start of data, but we * cut down the amount left by the amount used. */ @@ -316,12 +348,15 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", write_path = 2; } else if ( (pos >= wcp->file_size) && + (wcp->offset + wcp->data_size == wcp->file_size) && (pos > wcp->offset + wcp->data_size) && (pos < wcp->offset + wcp->alloc_size) ) { /* * Non-contiguous write part of which fits within - * the cache buffer and is extending the file. + * the cache buffer and is extending the file + * and the cache contents reflect the current + * data up to the current end of the file. */ size_t data_used; @@ -348,10 +383,11 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", wcp->data_size = pos + data_used - wcp->offset; /* - * Update the known file length. + * Update the file size if changed. */ - wcp->file_size = wcp->offset + wcp->data_size; + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; /* * If we used all the data then @@ -392,7 +428,7 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne */ if(pos + n > wcp->file_size) - wcp->file_size = pos + n; + fsp->size = wcp->file_size = pos + n; /* * If write would fit in the cache, and is larger than @@ -404,8 +440,16 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne if ( n <= wcp->alloc_size && n > wcp->data_size) { cache_flush_needed = True; } else { - DO_PROFILE_INC(writecache_direct_writes); - return real_write_file(fsp, data, pos, n); + ssize_t ret = real_write_file(fsp, data, pos, n); + + DO_PROFILE_INC(writecache_direct_writes); + if (ret == -1) + return ret; + + if (pos + ret > wcp->file_size) + fsp->size = wcp->file_size = pos + ret; + + return ret; } write_path = 4; @@ -413,7 +457,7 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne } if(wcp->data_size > wcp->file_size) - wcp->file_size = wcp->data_size; + fsp->size = wcp->file_size = wcp->data_size; if (cache_flush_needed) { DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ @@ -431,8 +475,13 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", */ if (n > wcp->alloc_size ) { - if(real_write_file(fsp, data, pos, n) == -1) + ssize_t ret = real_write_file(fsp, data, pos, n); + if (ret == -1) return -1; + + if (pos + ret > wcp->file_size) + fsp->size = wcp->file_size = pos + n; + DO_PROFILE_INC(writecache_direct_writes); return total_written + n; } @@ -455,7 +504,16 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", DO_PROFILE_INC(writecache_num_write_caches); } wcp->data_size += n; - DEBUG(9,("cache return %u\n", (unsigned int)n)); + + /* + * Update the file size if changed. + */ + + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n", + (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n)); + total_written += n; return total_written; /* .... that's a write :) */ } @@ -482,10 +540,8 @@ void delete_write_cache(files_struct *fsp) SMB_ASSERT(wcp->data_size == 0); - free(wcp->data); - free(wcp); - - fsp->wcp = NULL; + SAFE_FREE(wcp->data); + SAFE_FREE(fsp->wcp); DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); @@ -518,10 +574,12 @@ static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) if((wcp->data = malloc(wcp->alloc_size)) == NULL) { DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n", (unsigned int)wcp->alloc_size )); - free(wcp); + SAFE_FREE(wcp); return False; } + memset(wcp->data, '\0', wcp->alloc_size ); + fsp->wcp = wcp; DO_PROFILE_INC(writecache_allocated_write_caches); allocated_write_caches++; @@ -538,8 +596,15 @@ static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) { + fsp->size = file_size; if(fsp->wcp) { - flush_write_cache(fsp, SIZECHANGE_FLUSH); + /* The cache *must* have been flushed before we do this. */ + if (fsp->wcp->data_size != 0) { + pstring msg; + slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \ +on file %s with write cache size = %u\n", fsp->fsp_name, fsp->wcp->data_size ); + smb_panic(msg); + } fsp->wcp->file_size = file_size; } } @@ -552,6 +617,7 @@ ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason) { write_cache *wcp = fsp->wcp; size_t data_size; + ssize_t ret; if(!wcp || !wcp->data_size) return 0; @@ -569,7 +635,16 @@ ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason) DO_PROFILE_INC(writecache_num_perfect_writes); #endif - return real_write_file(fsp, wcp->data, wcp->offset, data_size); + ret = real_write_file(fsp, wcp->data, wcp->offset, data_size); + + /* + * Ensure file size if kept up to date if write extends file. + */ + + if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) + wcp->file_size = wcp->offset + ret; + + return ret; } /******************************************************************* diff --git a/source/smbd/filename.c b/source/smbd/filename.c index bdbcd81b644..601c488fc9c 100644 --- a/source/smbd/filename.c +++ b/source/smbd/filename.c @@ -27,7 +27,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern BOOL case_sensitive; extern BOOL case_preserve; extern BOOL short_case_preserve; @@ -293,7 +292,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, } else { pstring rest; - /* Stat failed - ensure we don't use it. */ + /* Stat failed - ensure we don't use it. */ ZERO_STRUCT(st); *rest = 0; @@ -330,7 +329,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, /* * Just the last part of the name doesn't exist. - * We may need to strupper() or strlower() it in case + * We may need to strupper() or strlower() it in case * this conversion is being used for file creation * purposes. If the filename is of mixed case then * don't normalise it. @@ -353,11 +352,14 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, } /* - * Restore the rest of the string. + * Restore the rest of the string. If the string was mangled the size + * may have changed. */ if (end) { - pstrcpy(start+strlen(start)+1,rest); end = start + strlen(start); + pstrcat(start,"/"); + pstrcat(start,rest); + *end = '\0'; } } /* end else */ @@ -495,11 +497,25 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d if (*dname == '.' && (strequal(dname,".") || strequal(dname,".."))) continue; + /* + * dname here is the unmangled name. + */ pstrcpy(name2,dname); if (!name_map_mangle(name2,False,True,SNUM(conn))) continue; - if ((mangled && mangled_equal(name,name2)) || fname_equal(name, name2)) { + /* + * At this point name2 is the mangled name, dname is the unmangled name. + * name is either mangled or not, depending on the state of the "mangled" + * variable. JRA. + */ + + /* + * Check mangled name against mangled name, or unmangled name + * against unmangled name. + */ + + if ((mangled && mangled_equal(name,name2)) || fname_equal(name, dname)) { /* we've found the file, change it's name and return */ if (docache) DirCacheAdd(path,name,dname,SNUM(conn)); diff --git a/source/smbd/files.c b/source/smbd/files.c index 27dfad7c483..3935a12442b 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - static int real_max_open_files; #define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files)) @@ -41,8 +39,22 @@ static files_struct *oplock_save_chain_fsp = NULL; static int files_used; /**************************************************************************** - find first available file slot + Return a unique number identifying this fsp over the life of this pid. +****************************************************************************/ + +static unsigned long get_gen_count(void) +{ + static unsigned long file_gen_counter; + + if ((++file_gen_counter) == 0) + return ++file_gen_counter; + return file_gen_counter; +} + +/**************************************************************************** + Find first available file slot. ****************************************************************************/ + files_struct *file_new(connection_struct *conn) { int i; @@ -92,6 +104,8 @@ files_struct *file_new(connection_struct *conn) ZERO_STRUCTP(fsp); fsp->fd = -1; fsp->conn = conn; + fsp->file_id = get_gen_count(); + GetTimeOfDay(&fsp->open_time); first_file = (i+1) % real_max_open_files; @@ -111,10 +125,10 @@ files_struct *file_new(connection_struct *conn) return fsp; } - /**************************************************************************** -close all open files for a connection + Close all open files for a connection. ****************************************************************************/ + void file_close_conn(connection_struct *conn) { files_struct *fsp, *next; @@ -128,7 +142,7 @@ void file_close_conn(connection_struct *conn) } /**************************************************************************** -initialise file structures + Initialise file structures. ****************************************************************************/ #define MAX_OPEN_FUDGEFACTOR 10 @@ -164,10 +178,10 @@ open files, %d are available.\n", request_max_open_files, real_max_open_files)); set_pipe_handle_offset(real_max_open_files); } - /**************************************************************************** -close files open by a specified vuid + Close files open by a specified vuid. ****************************************************************************/ + void file_close_user(int vuid) { files_struct *fsp, *next; @@ -180,13 +194,32 @@ void file_close_user(int vuid) } } +/**************************************************************************** + Find a fsp given a file descriptor. +****************************************************************************/ + +files_struct *file_find_fd(int fd) +{ + int count=0; + files_struct *fsp; + + for (fsp=Files;fsp;fsp=fsp->next,count++) { + if (fsp->fd == fd) { + if (count > 10) { + DLIST_PROMOTE(Files, fsp); + } + return fsp; + } + } + + return NULL; +} /**************************************************************************** - Find a fsp given a device, inode and timevalue - If this is from a kernel oplock break request then tval may be NULL. + Find a fsp given a device, inode and file_id. ****************************************************************************/ -files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval) +files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id) { int count=0; files_struct *fsp; @@ -195,8 +228,7 @@ files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval if (fsp->fd != -1 && fsp->dev == dev && fsp->inode == inode && - (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True ) && - (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True )) { + fsp->file_id == file_id ) { if (count > 10) { DLIST_PROMOTE(Files, fsp); } @@ -260,8 +292,9 @@ files_struct *file_find_di_next(files_struct *start_fsp) } /**************************************************************************** -find a fsp that is open for printing + Find a fsp that is open for printing. ****************************************************************************/ + files_struct *file_find_print(void) { files_struct *fsp; @@ -273,10 +306,10 @@ files_struct *file_find_print(void) return NULL; } - /**************************************************************************** -sync open files on a connection + Sync open files on a connection. ****************************************************************************/ + void file_sync_all(connection_struct *conn) { files_struct *fsp, *next; @@ -289,10 +322,10 @@ void file_sync_all(connection_struct *conn) } } - /**************************************************************************** -free up a fsp + Free up a fsp. ****************************************************************************/ + void file_free(files_struct *fsp) { DLIST_REMOVE(Files, fsp); @@ -311,19 +344,20 @@ void file_free(files_struct *fsp) if (fsp == chain_fsp) chain_fsp = NULL; - free(fsp); + SAFE_FREE(fsp); } - /**************************************************************************** -get a fsp from a packet given the offset of a 16 bit fnum + Get a fsp from a packet given the offset of a 16 bit fnum. ****************************************************************************/ + files_struct *file_fsp(char *buf, int where) { int fnum, count=0; files_struct *fsp; - if (chain_fsp) return chain_fsp; + if (chain_fsp) + return chain_fsp; fnum = SVAL(buf, where); @@ -340,7 +374,7 @@ files_struct *file_fsp(char *buf, int where) } /**************************************************************************** - Reset the chained fsp - done at the start of a packet reply + Reset the chained fsp - done at the start of a packet reply. ****************************************************************************/ void file_chain_reset(void) @@ -360,6 +394,7 @@ void file_chain_save(void) /**************************************************************************** Restore the chained fsp - done after an oplock break. ****************************************************************************/ + void file_chain_restore(void) { chain_fsp = oplock_save_chain_fsp; diff --git a/source/smbd/groupname.c b/source/smbd/groupname.c index d44e9a7a39c..2c7440d75a7 100644 --- a/source/smbd/groupname.c +++ b/source/smbd/groupname.c @@ -22,7 +22,6 @@ #ifdef USING_GROUPNAME_MAP #include "includes.h" -extern int DEBUGLEVEL; extern DOM_SID global_sam_sid; @@ -53,11 +52,9 @@ static void delete_groupname_map_list(void) groupname_map_entry *gmep; while((gmep = (groupname_map_entry *)ubi_slRemHead( &groupname_map_list )) != NULL) { - if(gmep->windows_name) - free(gmep->windows_name); - if(gmep->unix_name) - free(gmep->unix_name); - free((char *)gmep); + SAFE_FREE(gmep->windows_name); + SAFE_FREE(gmep->unix_name); + SAFE_FREE(gmep); } } @@ -188,11 +185,9 @@ Error was %s.\n", unixname, strerror(errno) )); if(new_ep->windows_name == NULL || new_ep->unix_name == NULL) { DEBUG(0,("load_groupname_map: malloc fail for names in groupname_map_entry.\n")); fclose(fp); - if(new_ep->windows_name != NULL) - free(new_ep->windows_name); - if(new_ep->unix_name != NULL) - free(new_ep->unix_name); - free((char *)new_ep); + SAFE_FREE(new_ep->windows_name); + SAFE_FREE(new_ep->unix_name); + SAFE_FREE(new_ep); file_lines_free(lines); return; } diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c index 3ec6d1f1cff..e1c3e7fe4d3 100644 --- a/source/smbd/ipc.c +++ b/source/smbd/ipc.c @@ -28,7 +28,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern int max_send; extern fstring local_machine; @@ -108,7 +107,7 @@ void send_trans_reply(char *outbuf, SCVAL(outbuf, smb_rcls, ERRDOS); } else { SIVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); - SIVAL(outbuf, smb_rcls, 0x80000000 | STATUS_BUFFER_OVERFLOW); + SIVAL(outbuf, smb_rcls, NT_STATUS_V(STATUS_BUFFER_OVERFLOW)); } } @@ -184,13 +183,13 @@ static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p) } if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) { - free(rdata); + SAFE_FREE(rdata); return False; } send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len); - free(rdata); + SAFE_FREE(rdata); return True; } @@ -394,7 +393,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int if((data = (char *)malloc(tdscnt)) == NULL) { DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt)); END_PROFILE(SMBtrans); - return(ERROR(ERRDOS,ERRnomem)); + return(ERROR_DOS(ERRDOS,ERRnomem)); } memcpy(data,smb_base(inbuf)+dsoff,dscnt); } @@ -403,7 +402,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int if((params = (char *)malloc(tpscnt)) == NULL) { DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt)); END_PROFILE(SMBtrans); - return(ERROR(ERRDOS,ERRnomem)); + return(ERROR_DOS(ERRDOS,ERRnomem)); } memcpy(params,smb_base(inbuf)+psoff,pscnt); } @@ -413,7 +412,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) { DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16)))); END_PROFILE(SMBtrans); - return(ERROR(ERRDOS,ERRnomem)); + return(ERROR_DOS(ERRDOS,ERRnomem)); } for (i=0;i<suwcnt;i++) setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD); @@ -443,14 +442,11 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int DEBUG(0,("reply_trans: %s in getting secondary trans response.\n", (smb_read_error == READ_ERROR) ? "error" : "timeout" )); } - if (params) - free(params); - if (data) - free(data); - if (setup) - free(setup); + SAFE_FREE(params); + SAFE_FREE(data); + SAFE_FREE(setup); END_PROFILE(SMBtrans); - return(ERROR(ERRSRV,ERRerror)); + return(ERROR_DOS(ERRSRV,ERRerror)); } show_msg(inbuf); @@ -510,12 +506,9 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int } - if (data) - free(data); - if (params) - free(params); - if (setup) - free(setup); + SAFE_FREE(data); + SAFE_FREE(params); + SAFE_FREE(setup); if (close_on_completion) close_cnum(conn,vuid); @@ -527,7 +520,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int if (outsize == 0) { END_PROFILE(SMBtrans); - return(ERROR(ERRSRV,ERRnosupport)); + return(ERROR_DOS(ERRSRV,ERRnosupport)); } END_PROFILE(SMBtrans); diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c index 3d8844d5be1..70d79a5f566 100644 --- a/source/smbd/lanman.c +++ b/source/smbd/lanman.c @@ -33,8 +33,6 @@ #endif #define CHECK_TYPES 0 -extern int DEBUGLEVEL; - extern fstring local_machine; extern pstring global_myname; extern fstring global_myworkgroup; @@ -748,6 +746,8 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel, PACKS(desc,"z","WinPrint"); /* pszPrProc */ PACKS(desc,"z",NULL); /* pszParms */ PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */ + /* "don't ask" that it's done this way to fix corrupted + Win9X/ME printer comments. */ if (!status) { PACKI(desc,"W",LPSTAT_OK); /* fsStatus */ } else { @@ -956,10 +956,8 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn, DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode)); - if (queue) - free(queue); - if (tmpdata) - free (tmpdata); + SAFE_FREE(queue); + SAFE_FREE(tmpdata); return(True); } @@ -1049,7 +1047,7 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, } } - if (subcntarr) free(subcntarr); + SAFE_FREE(subcntarr); *rdata_len = desc.usedlen; *rparam_len = 8; @@ -1060,11 +1058,11 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, SSVAL(*rparam,6,queuecnt); for (i = 0; i < queuecnt; i++) { - if (queue && queue[i]) free(queue[i]); + if (queue) SAFE_FREE(queue[i]); } - if (queue) free(queue); - if (status) free(status); + SAFE_FREE(queue); + SAFE_FREE(status); return True; } @@ -1137,13 +1135,13 @@ static int get_server_info(uint32 servertype, struct srv_info_struct *ts; alloced += 10; - ts = (struct srv_info_struct *)Realloc(*servers,sizeof(**servers)*alloced); + ts = (struct srv_info_struct *) + Realloc(*servers,sizeof(**servers)*alloced); if (!ts) { DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n")); return(0); } - else - *servers = ts; + else *servers = ts; memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count)); } s = &(*servers)[count]; @@ -1414,7 +1412,7 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param SSVAL(*rparam,4,counted); SSVAL(*rparam,6,counted+missed); - if (servers) free(servers); + SAFE_FREE(servers); DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", domain,uLevel,counted,counted+missed)); @@ -1527,7 +1525,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel, if (uLevel > 0) { int type; - CVAL(p,13) = 0; + SCVAL(p,13,0); type = STYPE_DISKTREE; if (lp_print_ok(snum)) type = STYPE_PRINTQ; if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC; @@ -1705,16 +1703,16 @@ static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,ch t = LocalTime(&unixdate); SIVAL(p,4,0); /* msecs ? */ - CVAL(p,8) = t->tm_hour; - CVAL(p,9) = t->tm_min; - CVAL(p,10) = t->tm_sec; - CVAL(p,11) = 0; /* hundredths of seconds */ + SCVAL(p,8,t->tm_hour); + SCVAL(p,9,t->tm_min); + SCVAL(p,10,t->tm_sec); + SCVAL(p,11,0); /* hundredths of seconds */ SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */ SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */ - CVAL(p,16) = t->tm_mday; - CVAL(p,17) = t->tm_mon + 1; + SCVAL(p,16,t->tm_mday); + SCVAL(p,17,t->tm_mon + 1); SSVAL(p,18,1900+t->tm_year); - CVAL(p,20) = t->tm_wday; + SCVAL(p,20,t->tm_wday); } @@ -1795,6 +1793,8 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False)) SSVAL(*rparam,0,NERR_badpass); } + + pdb_free_sam(sampass); } /* @@ -1830,6 +1830,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param { SSVAL(*rparam,0,NERR_Success); } + pdb_free_sam(sampass); } memset((char *)pass1,'\0',sizeof(fstring)); @@ -1911,6 +1912,7 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param char *p = skip_string(str2,1); int jobid, errcode; extern struct current_user current_user; + WERROR werr = WERR_OK; jobid = SVAL(p,0); @@ -1931,19 +1933,22 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param switch (function) { case 81: /* delete */ - if (print_job_delete(¤t_user, jobid, &errcode)) + if (print_job_delete(¤t_user, jobid, &werr)) errcode = NERR_Success; break; case 82: /* pause */ - if (print_job_pause(¤t_user, jobid, &errcode)) + if (print_job_pause(¤t_user, jobid, &werr)) errcode = NERR_Success; break; case 83: /* resume */ - if (print_job_resume(¤t_user, jobid, &errcode)) + if (print_job_resume(¤t_user, jobid, &werr)) errcode = NERR_Success; break; } + if (!W_ERROR_IS_OK(werr)) + errcode = W_ERROR_V(werr); + out: SSVAL(*rparam,0,errcode); SSVAL(*rparam,2,0); /* converter word */ @@ -1965,6 +1970,7 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param char *QueueName = skip_string(str2,1); int errcode = NERR_notsupported; int snum; + WERROR werr = WERR_OK; extern struct current_user current_user; /* check it's a supported varient */ @@ -1984,16 +1990,17 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param switch (function) { case 74: /* Pause queue */ - if (print_queue_pause(¤t_user, snum, &errcode)) errcode = NERR_Success; + if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success; break; case 75: /* Resume queue */ - if (print_queue_resume(¤t_user, snum, &errcode)) errcode = NERR_Success; + if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success; break; case 103: /* Purge */ - if (print_queue_purge(¤t_user, snum, &errcode)) errcode = NERR_Success; + if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success; break; } + if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr); out: SSVAL(*rparam,0,errcode); SSVAL(*rparam,2,0); /* converter word */ @@ -2162,7 +2169,7 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par pstrcpy(comment,servers[i].comment); } } - if (servers) free(servers); + SAFE_FREE(servers); SCVAL(p,0,lp_major_announce_version()); SCVAL(p,1,lp_minor_announce_version()); @@ -2827,8 +2834,8 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para SSVAL(*rparam,2,0); SSVAL(*rparam,4,desc.neededlen); - if (queue) free(queue); - if (tmpdata) free(tmpdata); + SAFE_FREE(queue); + SAFE_FREE(tmpdata); DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); return(True); @@ -2897,7 +2904,7 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa SSVAL(*rparam,4,succnt); SSVAL(*rparam,6,count); - if (queue) free(queue); + SAFE_FREE(queue); DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); return(True); @@ -3016,7 +3023,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par SSVAL(*rparam,4,desc.neededlen); DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); - if (tmpdata) free (tmpdata); + SAFE_FREE(tmpdata); return(True); } @@ -3267,35 +3274,44 @@ struct int,int,char **,char **,int *,int *); int flags; } api_commands[] = { - {"RNetShareEnum", 0, api_RNetShareEnum,0}, - {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0}, - {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0}, - {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0}, - {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0}, - {"NetUserGetGroups", 59, api_NetUserGetGroups,0}, - {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0}, - {"DosPrintQEnum", 69, api_DosPrintQEnum,0}, - {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0}, - {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0}, - {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0}, - {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0}, - {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0}, - {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0}, - {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0}, - {"RDosPrintJobResume",83, api_RDosPrintJobDel,0}, - {"WPrintDestEnum", 84, api_WPrintDestEnum,0}, - {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0}, - {"NetRemoteTOD", 91, api_NetRemoteTOD,0}, - {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0}, - {"NetServerEnum", 104, api_RNetServerEnum,0}, - {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0}, - {"SetUserPassword", 115, api_SetUserPassword,0}, - {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0}, - {"PrintJobInfo", 147, api_PrintJobInfo,0}, - {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0}, - {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0}, - {"WPrintPortEnum", 207, api_WPrintPortEnum,0}, - {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0}, + {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum,0}, + {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo,0}, +#if 0 /* Not yet implemented. */ + {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd,0}, +#endif + {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo,0}, +#if 0 /* Not yet implemented. */ + {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum,0}, +#endif + {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers,0}, +#if 0 /* Not yet implemented. */ + {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum,0}, +#endif + {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo,0}, + {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups,0}, + {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo,0}, + {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum,0}, + {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo,0}, + {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl,0}, + {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl,0}, + {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate,0}, + {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo,0}, + {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel,0}, + {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel,0}, + {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0}, + {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum,0}, + {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo,0}, + {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD,0}, + {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl,0}, + {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum,0}, + {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0}, + {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword,0}, + {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon,0}, + {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo,0}, + {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum,0}, + {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0}, + {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum,0}, + {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0}, {NULL, -1, api_Unsupported,0}}; @@ -3364,10 +3380,8 @@ int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char * send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False); - if (rdata ) - free(rdata); - if (rparam) - free(rparam); + SAFE_FREE(rdata); + SAFE_FREE(rparam); return -1; } diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c index d6d470c2dab..3d214d46589 100644 --- a/source/smbd/mangle.c +++ b/source/smbd/mangle.c @@ -52,7 +52,6 @@ * External Variables... */ -extern int DEBUGLEVEL; /* Global debug level. */ extern int case_default; /* Are conforming 8.3 names all upper or lower? */ extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */ @@ -466,7 +465,7 @@ static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr ) static void cache_free_entry( ubi_trNodePtr WarrenZevon ) { ZERO_STRUCTP(WarrenZevon); - free( WarrenZevon ); + SAFE_FREE( WarrenZevon ); } /* cache_free_entry */ /* ************************************************************************** ** @@ -633,7 +632,7 @@ BOOL check_mangled_cache( char *s ) { /* Replace the saved_ext as it was truncated. */ (void)pstrcat( s, saved_ext ); - free(saved_ext); + SAFE_FREE(saved_ext); } return( False ); } @@ -649,7 +648,7 @@ BOOL check_mangled_cache( char *s ) { /* Replace the saved_ext as it was truncated. */ (void)pstrcat( s, saved_ext ); - free(saved_ext); + SAFE_FREE(saved_ext); } DEBUG( 3, ("as %s\n", s) ); @@ -1017,7 +1016,7 @@ BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum) if(tmp != NULL) { cache_mangled_name(OutName, tmp); - free(tmp); + SAFE_FREE(tmp); } } diff --git a/source/smbd/message.c b/source/smbd/message.c index b3da3f2b611..0097b15b8b4 100644 --- a/source/smbd/message.c +++ b/source/smbd/message.c @@ -27,8 +27,6 @@ #include "includes.h" /* look in server.c for some explanation of these variables */ -extern int DEBUGLEVEL; - static char msgbuf[1600]; static int msgpos=0; @@ -113,7 +111,7 @@ int reply_sends(connection_struct *conn, if (! (*lp_msg_command())) { END_PROFILE(SMBsends); - return(ERROR(ERRSRV,ERRmsgoff)); + return(ERROR_DOS(ERRSRV,ERRmsgoff)); } outsize = set_message(outbuf,0,0,True); @@ -154,7 +152,7 @@ int reply_sendstrt(connection_struct *conn, if (! (*lp_msg_command())) { END_PROFILE(SMBsendstrt); - return(ERROR(ERRSRV,ERRmsgoff)); + return(ERROR_DOS(ERRSRV,ERRmsgoff)); } outsize = set_message(outbuf,1,0,True); @@ -188,7 +186,7 @@ int reply_sendtxt(connection_struct *conn, if (! (*lp_msg_command())) { END_PROFILE(SMBsendtxt); - return(ERROR(ERRSRV,ERRmsgoff)); + return(ERROR_DOS(ERRSRV,ERRmsgoff)); } outsize = set_message(outbuf,0,0,True); @@ -219,7 +217,7 @@ int reply_sendend(connection_struct *conn, if (! (*lp_msg_command())) { END_PROFILE(SMBsendend); - return(ERROR(ERRSRV,ERRmsgoff)); + return(ERROR_DOS(ERRSRV,ERRmsgoff)); } outsize = set_message(outbuf,0,0,True); diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c index 25419caf625..1f5de570c66 100644 --- a/source/smbd/negprot.c +++ b/source/smbd/negprot.c @@ -21,7 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern int Protocol; extern int max_recv; extern fstring global_myworkgroup; @@ -158,7 +157,7 @@ reply for the nt protocol static int reply_nt1(char *outbuf) { /* dual names + lock_and_read + nt SMBs + remote API calls */ - int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_LEVEL_II_OPLOCKS| + int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_LEVEL_II_OPLOCKS|CAP_STATUS32| (lp_unix_extensions() ? CAP_UNIX : 0) | (lp_nt_smb_support() ? CAP_NT_SMBS | CAP_RPC_REMOTE_APIS : 0) | ((lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) ? CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_W2K_SMBS : 0) | @@ -217,7 +216,7 @@ static int reply_nt1(char *outbuf) set_message(outbuf,17,data_len,True); pstrcpy(smb_buf(outbuf)+crypt_len, global_myworkgroup); - CVAL(outbuf,smb_vwv1) = secword; + SCVAL(outbuf,smb_vwv1,secword); SSVALS(outbuf,smb_vwv16+1,crypt_len); if (doencrypt) memcpy(smb_buf(outbuf), cryptkey, 8); diff --git a/source/smbd/noquotas.c b/source/smbd/noquotas.c index 5c55bb47c8e..a6951d97fc5 100644 --- a/source/smbd/noquotas.c +++ b/source/smbd/noquotas.c @@ -25,7 +25,7 @@ * Needed for auto generation of proto.h. */ -BOOL disk_quotas(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) { (*bsize) = 512; /* This value should be ignored */ diff --git a/source/smbd/notify.c b/source/smbd/notify.c index d0966289fe7..52df3558aa7 100644 --- a/source/smbd/notify.c +++ b/source/smbd/notify.c @@ -22,16 +22,13 @@ #include "includes.h" -extern int DEBUGLEVEL; -extern uint32 global_client_caps; - static struct cnotify_fns *cnotify; /**************************************************************************** This is the structure to queue to implement NT change notify. It consists of smb_size bytes stored from the transact command (to keep the mid, tid etc around). - Plus the fid to examine and notify private data + Plus the fid to examine and notify private data. *****************************************************************************/ struct change_notify { @@ -48,26 +45,14 @@ static struct change_notify *change_notify_list; /**************************************************************************** Setup the common parts of the return packet and send it. *****************************************************************************/ -static void change_notify_reply_packet(char *inbuf, uint32 error_code) +static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code) { char outbuf[smb_size+38]; memset(outbuf, '\0', sizeof(outbuf)); construct_reply_common(inbuf, outbuf); - /* - * If we're returning a 'too much in the directory changed' we need to - * set this is an NT error status flags. If we don't then the (probably - * untested) code in the NT redirector has a bug in that it doesn't re-issue - * the change notify.... Ah - I *love* it when I get so deeply into this I - * can even determine how MS failed to test stuff and why.... :-). JRA. - */ - - if (global_client_caps & CAP_STATUS32) { - ERROR(0,error_code); - } else { - ERROR(ERRDOS,STATUS_NOTIFY_ENUM_DIR); - } + ERROR_NT(error_code); /* * Seems NT needs a transact command with an error code @@ -76,26 +61,26 @@ static void change_notify_reply_packet(char *inbuf, uint32 error_code) set_message(outbuf,18,0,False); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("change_notify_reply_packet: send_smb failed.\n"); + exit_server("change_notify_reply_packet: send_smb failed."); } /**************************************************************************** -remove an entry from the list and free it, also closing any -directory handle if necessary -Notice the horrible stuff we have to do because this is a singly linked list. + Remove an entry from the list and free it, also closing any + directory handle if necessary. *****************************************************************************/ + static void change_notify_remove(struct change_notify *cnbp) { cnotify->remove_notify(cnbp->change_data); DLIST_REMOVE(change_notify_list, cnbp); ZERO_STRUCTP(cnbp); - free(cnbp); + SAFE_FREE(cnbp); } - /**************************************************************************** Delete entries by fnum from the change notify pending queue. *****************************************************************************/ + void remove_pending_change_notify_requests_by_fid(files_struct *fsp) { struct change_notify *cnbp, *next; @@ -111,6 +96,7 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp) /**************************************************************************** Delete entries by mid from the change notify pending queue. Always send reply. *****************************************************************************/ + void remove_pending_change_notify_requests_by_mid(int mid) { struct change_notify *cnbp, *next; @@ -128,6 +114,7 @@ void remove_pending_change_notify_requests_by_mid(int mid) Delete entries by filename and cnum from the change notify pending queue. Always send reply. *****************************************************************************/ + void remove_pending_change_notify_requests_by_filename(files_struct *fsp) { struct change_notify *cnbp, *next; @@ -148,6 +135,7 @@ void remove_pending_change_notify_requests_by_filename(files_struct *fsp) /**************************************************************************** Return true if there are pending change notifies. ****************************************************************************/ + int change_notify_timeout(void) { return cnotify->select_time; @@ -158,6 +146,7 @@ int change_notify_timeout(void) Returns True if there are still outstanding change notify requests on the queue. *****************************************************************************/ + BOOL process_pending_change_notify_queue(time_t t) { struct change_notify *cnbp, *next; @@ -167,8 +156,9 @@ BOOL process_pending_change_notify_queue(time_t t) next=cnbp->next; vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid); - + if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) { + DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name )); change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR); change_notify_remove(cnbp); } @@ -178,11 +168,12 @@ BOOL process_pending_change_notify_queue(time_t t) } /**************************************************************************** - * Now queue an entry on the notify change list. - * We only need to save smb_size bytes from this incoming packet - * as we will always by returning a 'read the directory yourself' - * error. + Now queue an entry on the notify change list. + We only need to save smb_size bytes from this incoming packet + as we will always by returning a 'read the directory yourself' + error. ****************************************************************************/ + BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags) { struct change_notify *cnbp; @@ -201,7 +192,7 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags); if (!cnbp->change_data) { - free(cnbp); + SAFE_FREE(cnbp); return False; } @@ -210,10 +201,10 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, return True; } - /**************************************************************************** -initialise the change notify subsystem + Initialise the change notify subsystem. ****************************************************************************/ + BOOL init_change_notify(void) { #if HAVE_KERNEL_CHANGE_NOTIFY diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c index a0a61569a8b..90eb88ac814 100644 --- a/source/smbd/notify_hash.c +++ b/source/smbd/notify_hash.c @@ -22,21 +22,20 @@ #include "includes.h" -extern int DEBUGLEVEL; - - struct change_data { time_t last_check_time; /* time we last checked this entry */ time_t modify_time; /* Info from the directory we're monitoring. */ time_t status_time; /* Info from the directory we're monitoring. */ time_t total_time; /* Total time of all directory entries - don't care if it wraps. */ unsigned int num_entries; /* Zero or the number of files in the directory. */ + unsigned int mode_sum; + unsigned char name_hash[16]; }; - /**************************************************************************** Create the hash we will use to determine if the contents changed. *****************************************************************************/ + static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, struct change_data *data, struct change_data *old_data) { @@ -50,7 +49,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, ZERO_STRUCTP(data); - if(vfs_stat(conn,path, &st) == -1) return False; + if(vfs_stat(conn,path, &st) == -1) + return False; data->modify_time = st.st_mtime; data->status_time = st.st_ctime; @@ -76,10 +76,9 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, * larger than the max time_t value). */ - if (!(flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE))) return True; - dp = OpenDir(conn, path, True); - if (dp == NULL) return False; + if (dp == NULL) + return False; data->num_entries = 0; @@ -91,7 +90,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, p = &full_name[fullname_len]; while ((fname = ReadDirName(dp))) { - if(strequal(fname, ".") || strequal(fname, "..")) continue; + if(strequal(fname, ".") || strequal(fname, "..")) + continue; data->num_entries++; safe_strcpy(p, fname, remaining_len); @@ -102,7 +102,31 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, * Do the stat - but ignore errors. */ vfs_stat(conn,full_name, &st); + + /* + * Always sum the times. + */ + data->total_time += (st.st_mtime + st.st_ctime); + + /* + * If requested hash the names. + */ + + if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_FILE)) { + int i; + unsigned char tmp_hash[16]; + mdfour(tmp_hash, (unsigned char *)fname, strlen(fname)); + for (i=0;i<16;i++) + data->name_hash[i] ^= tmp_hash[i]; + } + + /* + * If requested sum the mode_t's. + */ + + if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SECURITY)) + data->mode_sum = st.st_mode; } CloseDir(dp); @@ -110,15 +134,16 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, return True; } - /**************************************************************************** -register a change notify request + Register a change notify request. *****************************************************************************/ + static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags) { struct change_data data; - if (!notify_hash(conn, path, flags, &data, NULL)) return NULL; + if (!notify_hash(conn, path, flags, &data, NULL)) + return NULL; data.last_check_time = time(NULL); @@ -129,16 +154,19 @@ static void *hash_register_notify(connection_struct *conn, char *path, uint32 fl Check if a change notify should be issued. A time of zero means instantaneous check - don't modify the last check time. *****************************************************************************/ + static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t) { struct change_data *data = (struct change_data *)datap; struct change_data data2; - if (t && t < data->last_check_time + lp_change_notify_timeout()) return False; + if (t && t < data->last_check_time + lp_change_notify_timeout()) + return False; - if (!become_user(conn,vuid)) return True; - if (!become_service(conn,True)) { - unbecome_user(); + if (!change_to_user(conn,vuid)) + return True; + if (!set_current_service(conn,True)) { + change_to_root_user(); return True; } @@ -146,31 +174,34 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, data2.modify_time != data->modify_time || data2.status_time != data->status_time || data2.total_time != data->total_time || - data2.num_entries != data->num_entries) { - unbecome_user(); + data2.num_entries != data->num_entries || + data2.mode_sum != data->mode_sum || + memcmp(data2.name_hash, data->name_hash, sizeof(data2.name_hash))) { + change_to_root_user(); return True; } if (t) data->last_check_time = t; - unbecome_user(); + change_to_root_user(); return False; } /**************************************************************************** -remove a change notify data structure + Remove a change notify data structure. *****************************************************************************/ + static void hash_remove_notify(void *datap) { - free(datap); + SAFE_FREE(datap); } - /**************************************************************************** -setup hash based change notify + Setup hash based change notify. ****************************************************************************/ + struct cnotify_fns *hash_notify_init(void) { static struct cnotify_fns cnotify; @@ -183,7 +214,6 @@ struct cnotify_fns *hash_notify_init(void) return &cnotify; } - /* change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess); change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR); diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c index f1e40793c85..96164a3199b 100644 --- a/source/smbd/notify_kernel.c +++ b/source/smbd/notify_kernel.c @@ -23,7 +23,6 @@ #if HAVE_KERNEL_CHANGE_NOTIFY -extern int DEBUGLEVEL; static VOLATILE sig_atomic_t fd_pending; static VOLATILE sig_atomic_t signals_received; static VOLATILE sig_atomic_t signals_processed; @@ -111,7 +110,7 @@ static void kernel_remove_notify(void *datap) } close(fd); } - free(data); + SAFE_FREE(data); DEBUG(3,("removed kernel change notify fd=%d\n", fd)); } diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index e913daef18a..110d7ed7d26 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -21,14 +21,12 @@ #include "includes.h" -extern int DEBUGLEVEL; extern int Protocol; extern int smb_read_error; extern int global_oplock_break; extern BOOL case_sensitive; extern BOOL case_preserve; extern BOOL short_case_preserve; -extern uint32 global_client_caps; static char *known_nt_pipes[] = { "\\LANMAN", @@ -64,8 +62,8 @@ struct generic_mapping file_generic_mapping = { HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_error, int eclass, uint32 ecode, - char *params, int paramsize, char *pdata, int datasize) +static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params, + int paramsize, char *pdata, int datasize) { extern int max_send; int data_to_send = datasize; @@ -84,8 +82,8 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_err set_message(outbuf,18,0,True); - if(nt_error != 0) { - ERROR_BOTH(nt_error,eclass,ecode); + if(NT_STATUS_V(nt_error)) { + ERROR_NT(nt_error); } /* @@ -95,7 +93,7 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_err if(params_to_send == 0 && data_to_send == 0) { if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_nt_replies: send_smb failed.\n"); + exit_server("send_nt_replies: send_smb failed."); return 0; } @@ -225,7 +223,7 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_err /* Send the packet */ if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_nt_replies: send_smb failed.\n"); + exit_server("send_nt_replies: send_smb failed."); pp += params_sent_thistime; pd += data_sent_thistime; @@ -397,7 +395,7 @@ static int map_create_disposition( uint32 create_disposition) return -1; } - DEBUG(10,("map_create_disposition: Mapped create_disposition %lx to %x\n", + DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n", (unsigned long)create_disposition, ret )); return ret; @@ -407,7 +405,7 @@ static int map_create_disposition( uint32 create_disposition) Utility function to map share modes. ****************************************************************************/ -static int map_share_mode( BOOL *pstat_open_only, char *fname, +static int map_share_mode( BOOL *pstat_open_only, char *fname, uint32 create_options, uint32 desired_access, uint32 share_access, uint32 file_attributes) { int smb_open_mode = -1; @@ -471,7 +469,7 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname, smb_open_mode = DOS_OPEN_RDONLY; } else { - DEBUG(0,("map_share_mode: Incorrect value %lx for desired_access to file %s\n", + DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n", (unsigned long)desired_access, fname)); return -1; } @@ -485,7 +483,7 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname, 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)); + DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode)); } /* @@ -497,7 +495,14 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname, 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)); + DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode)); + } + + if (create_options & FILE_DELETE_ON_CLOSE) { + /* Implicit delete access requested... */ + smb_open_mode |= DELETE_ACCESS_REQUESTED; + smb_open_mode |= DELETE_ON_CLOSE_FLAG; + DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = 0x%x\n", smb_open_mode)); } /* Add in the requested share mode. */ @@ -523,8 +528,8 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname, if(file_attributes & FILE_FLAG_WRITE_THROUGH) smb_open_mode |= FILE_SYNC_OPENMODE; - DEBUG(10,("map_share_mode: Mapped desired access %lx, share access %lx, file attributes %lx \ -to open_mode %x\n", (unsigned long)desired_access, (unsigned long)share_access, + DEBUG(10,("map_share_mode: Mapped desired access 0x%lx, share access 0x%lx, file attributes 0x%lx \ +to open_mode 0x%x\n", (unsigned long)desired_access, (unsigned long)share_access, (unsigned long)file_attributes, smb_open_mode )); return smb_open_mode; @@ -546,14 +551,14 @@ static int nt_open_pipe(char *fname, connection_struct *conn, /* See if it is one we want to handle. */ if (lp_disable_spoolss() && strequal(fname, "\\spoolss")) - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); for( i = 0; known_nt_pipes[i]; i++ ) if( strequal(fname,known_nt_pipes[i])) break; if ( known_nt_pipes[i] == NULL ) - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); /* Strip \\ off the name. */ fname++; @@ -562,7 +567,7 @@ static int nt_open_pipe(char *fname, connection_struct *conn, p = open_rpc_pipe_p(fname, conn, vuid); if (!p) - return(ERROR(ERRSRV,ERRnofids)); + return(ERROR_DOS(ERRSRV,ERRnofids)); *ppnum = p->pnum; @@ -657,7 +662,7 @@ int reply_ntcreate_and_X(connection_struct *conn, return do_ntcreate_pipe_open(conn,inbuf,outbuf,length,bufsize); } else { END_PROFILE(SMBntcreateX); - return(ERROR(ERRDOS,ERRbadaccess)); + return(ERROR_DOS(ERRDOS,ERRbadaccess)); } } @@ -669,87 +674,87 @@ int reply_ntcreate_and_X(connection_struct *conn, if((smb_ofun = map_create_disposition( create_disposition )) == -1) { END_PROFILE(SMBntcreateX); - return(ERROR(ERRDOS,ERRbadaccess)); + return(ERROR_DOS(ERRDOS,ERRbadaccess)); } /* * Get the file name. */ - if(root_dir_fid != 0) { - /* - * This filename is relative to a directory fid. - */ - files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid); - size_t dir_name_len; + if(root_dir_fid != 0) { + /* + * This filename is relative to a directory fid. + */ + files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid); + size_t dir_name_len; - if(!dir_fsp) { - END_PROFILE(SMBntcreateX); - return(ERROR(ERRDOS,ERRbadfid)); - } + if(!dir_fsp) { + END_PROFILE(SMBntcreateX); + return(ERROR_DOS(ERRDOS,ERRbadfid)); + } - if(!dir_fsp->is_directory) { - /* - * Check to see if this is a mac fork of some kind. - */ + if(!dir_fsp->is_directory) { + /* + * Check to see if this is a mac fork of some kind. + */ - get_filename(&fname[0], inbuf, smb_buf(inbuf)-inbuf, - smb_buflen(inbuf),fname_len); + get_filename(&fname[0], inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); - if( strchr(fname, ':')) { - END_PROFILE(SMBntcreateX); - return(ERROR_BOTH(NT_STATUS_OBJECT_PATH_NOT_FOUND,ERRDOS,ERRbadpath)); - } - END_PROFILE(SMBntcreateX); - return(ERROR(ERRDOS,ERRbadfid)); - } + if( strchr(fname, ':')) { + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } + END_PROFILE(SMBntcreateX); + return(ERROR_DOS(ERRDOS,ERRbadfid)); + } - /* - * Copy in the base directory name. - */ + /* + * Copy in the base directory name. + */ - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); + pstrcpy( fname, dir_fsp->fsp_name ); + dir_name_len = strlen(fname); - /* - * Ensure it ends in a '\'. - */ + /* + * Ensure it ends in a '\'. + */ - if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') { - pstrcat(fname, "\\"); - dir_name_len++; - } + if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') { + pstrcat(fname, "\\"); + dir_name_len++; + } - /* - * This next calculation can refuse a correct filename if we're dealing - * with the Win2k unicode bug, but that would be rare. JRA. - */ + /* + * This next calculation can refuse a correct filename if we're dealing + * with the Win2k unicode bug, but that would be rare. JRA. + */ - if(fname_len + dir_name_len >= sizeof(pstring)) { - END_PROFILE(SMBntcreateX); - return(ERROR(ERRSRV,ERRfilespecs)); - } + if(fname_len + dir_name_len >= sizeof(pstring)) { + END_PROFILE(SMBntcreateX); + return(ERROR_DOS(ERRSRV,ERRfilespecs)); + } - get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf, - smb_buflen(inbuf),fname_len); + get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); - } else { + } else { - get_filename(fname, inbuf, smb_buf(inbuf)-inbuf, - smb_buflen(inbuf),fname_len); - } + get_filename(fname, inbuf, smb_buf(inbuf)-inbuf, + smb_buflen(inbuf),fname_len); + } /* * Now contruct the smb_open_mode value from the filename, - * desired access and the share access. + * desired access and the share access. */ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - if((smb_open_mode = map_share_mode(&stat_open_only, fname, desired_access, + if((smb_open_mode = map_share_mode(&stat_open_only, fname, create_options, desired_access, share_access, file_attributes)) == -1) { END_PROFILE(SMBntcreateX); - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -776,15 +781,12 @@ int reply_ntcreate_and_X(connection_struct *conn, if(create_options & FILE_DIRECTORY_FILE) { oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); restore_case_semantics(file_attributes); if(!fsp) { - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBntcreateX); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -837,19 +839,18 @@ int reply_ntcreate_and_X(connection_struct *conn, if (create_options & FILE_NON_DIRECTORY_FILE) { restore_case_semantics(file_attributes); + SSVAL(outbuf, smb_flg2, + SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); END_PROFILE(SMBntcreateX); - return(ERROR_BOTH(NT_STATUS_FILE_IS_A_DIRECTORY,ERRDOS,ERRbadaccess)); + return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY); } oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); if(!fsp) { restore_case_semantics(file_attributes); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBntcreateX); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -875,12 +876,8 @@ int reply_ntcreate_and_X(connection_struct *conn, } else { - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - restore_case_semantics(file_attributes); + set_bad_path_error(errno, bad_path); END_PROFILE(SMBntcreateX); return(UNIXERROR(ERRDOS,ERRnoaccess)); @@ -897,7 +894,7 @@ int reply_ntcreate_and_X(connection_struct *conn, if (!fsp->is_directory && (fmode & aDIR)) { close_file(fsp,False); END_PROFILE(SMBntcreateX); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } /* @@ -912,7 +909,12 @@ int reply_ntcreate_and_X(connection_struct *conn, if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) smb_action |= EXTENDED_OPLOCK_GRANTED; +#if 1 /* JRATEST */ + /* W2K sends back 42 words here ! */ + set_message(outbuf,42,0,True); +#else set_message(outbuf,34,0,True); +#endif p = outbuf + smb_vwv2; @@ -921,10 +923,10 @@ int reply_ntcreate_and_X(connection_struct *conn, * exclusive & batch here. */ - if (smb_action & EXTENDED_OPLOCK_GRANTED) - SCVAL(p,0, BATCH_OPLOCK_RETURN); + if (smb_action & EXTENDED_OPLOCK_GRANTED) + SCVAL(p,0, BATCH_OPLOCK_RETURN); else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) - SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); + SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); else SCVAL(p,0,NO_OPLOCK_RETURN); @@ -990,7 +992,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, if(total_parameter_count < 54) { DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); } fname_len = MIN(((uint32)IVAL(params,44)),((uint32)sizeof(fname)-1)); @@ -1004,7 +1006,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, /* Realloc the size of parameters and data we will return */ params = Realloc(*ppparams, 69); if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); *ppparams = params; @@ -1030,7 +1032,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); /* Send the required number of replies */ - send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, params, 69, *ppdata, 0); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); return -1; } @@ -1164,7 +1166,7 @@ static int call_nt_transact_create(connection_struct *conn, return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, bufsize, ppsetup, ppparams, ppdata); else - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); } /* @@ -1173,7 +1175,7 @@ static int call_nt_transact_create(connection_struct *conn, if(total_parameter_count < 54) { DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); } flags = IVAL(params,0); @@ -1193,7 +1195,7 @@ static int call_nt_transact_create(connection_struct *conn, */ if((smb_ofun = map_create_disposition( create_disposition )) == -1) - return(ERROR(ERRDOS,ERRbadmem)); + return ERROR_DOS(ERRDOS,ERRbadmem); /* * Get the file name. @@ -1208,7 +1210,7 @@ static int call_nt_transact_create(connection_struct *conn, size_t dir_name_len; if(!dir_fsp) - return(ERROR(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); if(!dir_fsp->is_directory) { /* @@ -1222,7 +1224,7 @@ static int call_nt_transact_create(connection_struct *conn, return(ERROR_BOTH(NT_STATUS_OBJECT_PATH_NOT_FOUND,ERRDOS,ERRbadpath)); } - return(ERROR(ERRDOS,ERRbadfid)); + return(ERROR_DOS(ERRDOS,ERRbadfid)); } /* @@ -1247,7 +1249,7 @@ static int call_nt_transact_create(connection_struct *conn, */ if(fname_len + dir_name_len >= sizeof(pstring)) - return(ERROR(ERRSRV,ERRfilespecs)); + return(ERROR_DOS(ERRSRV,ERRfilespecs)); get_filename_transact(&fname[dir_name_len], params, 53, total_parameter_count - 53 - fname_len, fname_len); @@ -1262,9 +1264,9 @@ static int call_nt_transact_create(connection_struct *conn, * and the share access. */ - if((smb_open_mode = map_share_mode( &stat_open_only, fname, desired_access, + if((smb_open_mode = map_share_mode( &stat_open_only, fname, create_options, desired_access, share_access, file_attributes)) == -1) - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; @@ -1295,14 +1297,11 @@ static int call_nt_transact_create(connection_struct *conn, * CreateDirectory() call. */ - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); if(!fsp) { restore_case_semantics(file_attributes); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1325,18 +1324,17 @@ static int call_nt_transact_create(connection_struct *conn, if (create_options & FILE_NON_DIRECTORY_FILE) { restore_case_semantics(file_attributes); - return(ERROR_BOTH(NT_STATUS_FILE_IS_A_DIRECTORY,ERRDOS, ERRbadaccess)); + SSVAL(outbuf, smb_flg2, + SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); + return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY); } oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); if(!fsp) { restore_case_semantics(file_attributes); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRnoaccess)); } #ifdef EROFS @@ -1360,12 +1358,8 @@ static int call_nt_transact_create(connection_struct *conn, } } else { - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - restore_case_semantics(file_attributes); + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1379,7 +1373,7 @@ static int call_nt_transact_create(connection_struct *conn, if (fmode & aDIR) { close_file(fsp,False); restore_case_semantics(file_attributes); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } /* @@ -1402,7 +1396,7 @@ static int call_nt_transact_create(connection_struct *conn, if (!set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) { close_file(fsp,False); restore_case_semantics(file_attributes); - return(ERROR(error_class, error_code)); + return ERROR_DOS(error_class, error_code); } restore_case_semantics(file_attributes); @@ -1410,7 +1404,7 @@ static int call_nt_transact_create(connection_struct *conn, /* Realloc the size of parameters and data we will return */ params = Realloc(*ppparams, 69); if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); *ppparams = params; @@ -1457,7 +1451,7 @@ static int call_nt_transact_create(connection_struct *conn, DEBUG(5,("call_nt_transact_create: open name = %s\n", fname)); /* Send the required number of replies */ - send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, params, 69, *ppdata, 0); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); return -1; } @@ -1515,10 +1509,10 @@ static int call_nt_transact_notify_change(connection_struct *conn, DEBUG(3,("call_nt_transact_notify_change\n")); if(!fsp) - return(ERROR(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); if((!fsp->is_directory) || (conn != fsp->conn)) - return(ERROR(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); if (!change_notify_set(inbuf, fsp, conn, flags)) { return(UNIXERROR(ERRDOS,ERRbadfid)); @@ -1539,30 +1533,30 @@ static int call_nt_transact_rename(connection_struct *conn, int bufsize, char **ppsetup, char **ppparams, char **ppdata) { - char *params = *ppparams; - pstring new_name; - files_struct *fsp = file_fsp(params, 0); - BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; - uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)), - ((uint32)sizeof(new_name)-1)); - int outsize = 0; - - CHECK_FSP(fsp, conn); - StrnCpy(new_name,params+4,fname_len); - new_name[fname_len] = '\0'; - - outsize = rename_internals(conn, inbuf, outbuf, fsp->fsp_name, + char *params = *ppparams; + pstring new_name; + files_struct *fsp = file_fsp(params, 0); + BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; + NTSTATUS status; + uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)), + ((uint32)sizeof(new_name)-1)); + + CHECK_FSP(fsp, conn); + StrnCpy(new_name,params+4,fname_len); + new_name[fname_len] = '\0'; + + status = rename_internals(conn, fsp->fsp_name, new_name, replace_if_exists); - if(outsize == 0) { - /* - * Rename was successful. - */ - send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, NULL, 0, NULL, 0); + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); - DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", - fsp->fsp_name, new_name)); + /* + * Rename was successful. + */ + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - outsize = -1; + DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", + fsp->fsp_name, new_name)); /* * Win2k needs a changenotify request response before it will @@ -1570,9 +1564,8 @@ static int call_nt_transact_rename(connection_struct *conn, */ process_pending_change_notify_queue((time_t)0); - } - return(outsize); + return -1; } /****************************************************************************** @@ -1593,7 +1586,7 @@ static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) return sd_size; } -/**************************************************************************n +/**************************************************************************** Reply to query a security descriptor - currently this is not implemented (it is planned to be though). Right now it just returns the same thing NT would when queried on a FAT filesystem. JRA. @@ -1615,19 +1608,19 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, files_struct *fsp = file_fsp(params,0); if(!fsp) - return(ERROR(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); params = Realloc(*ppparams, 4); if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); *ppparams = params; if ((mem_ctx = talloc_init()) == NULL) { DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); } /* @@ -1650,7 +1643,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, if(max_data_count < sd_size) { - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, ERRDOS, 122, + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, params, 4, *ppdata, 0); talloc_destroy(mem_ctx); return -1; @@ -1663,7 +1656,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, data = Realloc(*ppdata, sd_size); if(data == NULL) { talloc_destroy(mem_ctx); - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); } *ppdata = data; @@ -1703,7 +1696,7 @@ security descriptor.\n")); talloc_destroy(mem_ctx); - send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, params, 4, data, (int)sd_size); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size); return -1; } @@ -1726,10 +1719,10 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, uint32 error_code; if(total_parameter_count < 8) - return(ERROR(ERRDOS,ERRbadfunc)); + return ERROR_DOS(ERRDOS,ERRbadfunc); if((fsp = file_fsp(params,0)) == NULL) - return(ERROR(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); if(!lp_nt_acl_support(SNUM(conn))) goto done; @@ -1740,11 +1733,11 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, (unsigned int)security_info_sent )); if (!set_sd( fsp, data, total_data_count, security_info_sent, &error_class, &error_code)) - return (ERROR(error_class, error_code)); + return ERROR_DOS(error_class, error_code); done: - send_nt_replies(inbuf, outbuf, bufsize, 0, 0, 0, NULL, 0, NULL, 0); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; } @@ -1759,10 +1752,10 @@ static int call_nt_transact_ioctl(connection_struct *conn, static BOOL logged_message = False; if(!logged_message) { - DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n")); + DEBUG(2,("call_nt_transact_ioctl: Currently not implemented.\n")); logged_message = True; /* Only print this once... */ } - return(ERROR_BOTH(NT_STATUS_NOT_IMPLEMENTED,ERRSRV,ERRnosupport)); + return ERROR_DOS(ERRSRV,ERRnosupport); } /**************************************************************************** @@ -1804,7 +1797,7 @@ due to being in oplock break state.\n" )); if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { END_PROFILE(SMBnttrans); - return (ERROR(ERRSRV,ERRaccess)); + return ERROR_DOS(ERRSRV,ERRaccess); } outsize = set_message(outbuf,0,0,True); @@ -1818,7 +1811,7 @@ due to being in oplock break state.\n" )); DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", CVAL(inbuf, smb_wct), 19 + (setup_count/2))); END_PROFILE(SMBnttrans); - return(ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } /* Allocate the space for the setup, the maximum needed parameters and data */ @@ -1837,7 +1830,7 @@ due to being in oplock break state.\n" )); safe_free(data); DEBUG(0,("reply_nttrans : Out of memory\n")); END_PROFILE(SMBnttrans); - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); } /* Copy the param and data bytes sent with this request into @@ -1846,7 +1839,7 @@ due to being in oplock break state.\n" )); num_data_sofar = data_count; if (parameter_count > total_parameter_count || data_count > total_data_count) - exit_server("reply_nttrans: invalid sizes in packet.\n"); + exit_server("reply_nttrans: invalid sizes in packet."); if(setup) { memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); @@ -1869,7 +1862,7 @@ due to being in oplock break state.\n" )); of the parameter/data bytes */ outsize = set_message(outbuf,0,0,True); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_nttrans: send_smb failed.\n"); + exit_server("reply_nttrans: send_smb failed."); while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { BOOL ret; @@ -1884,14 +1877,11 @@ due to being in oplock break state.\n" )); DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", (smb_read_error == READ_ERROR) ? "error" : "timeout" )); } - if(params) - free(params); - if(data) - free(data); - if(setup) - free(setup); + SAFE_FREE(params); + SAFE_FREE(data); + SAFE_FREE(setup); END_PROFILE(SMBnttrans); - return(ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } /* Revise total_params and total_data in case they have changed downwards */ @@ -1900,7 +1890,7 @@ due to being in oplock break state.\n" )); num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount)); num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount)); if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) - exit_server("reply_nttrans2: data overflow in secondary nttrans packet\n"); + exit_server("reply_nttrans2: data overflow in secondary nttrans packet"); memcpy( ¶ms[ IVAL(inbuf, smb_nts_ParameterDisplacement)], smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count); @@ -1910,8 +1900,7 @@ due to being in oplock break state.\n" )); } if (Protocol >= PROTOCOL_NT1) { - uint16 flg2 = SVAL(outbuf,smb_flg2); - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */ } /* Now we must call the relevant NT_TRANS function */ @@ -1961,14 +1950,11 @@ due to being in oplock break state.\n" )); default: /* Error in request */ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); - if(setup) - free(setup); - if(params) - free(params); - if(data) - free(data); + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); END_PROFILE(SMBnttrans); - return (ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } /* As we do not know how many data packets will need to be @@ -1978,12 +1964,9 @@ due to being in oplock break state.\n" )); an error packet. */ - if(setup) - free(setup); - if(params) - free(params); - if(data) - free(data); + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); END_PROFILE(SMBnttrans); return outsize; /* If a correct response was needed the call_nt_transact_xxxx calls have already sent it. If outsize != -1 then it is diff --git a/source/smbd/open.c b/source/smbd/open.c index 6919249a226..9cefcc9b45e 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -22,8 +22,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - extern userdom_struct current_user_info; extern uint16 global_oplock_port; extern BOOL global_client_failed_oplock_break; @@ -36,8 +34,10 @@ static int fd_open(struct connection_struct *conn, char *fname, int flags, mode_t mode) { int fd; -#ifdef O_NONBLOCK - flags |= O_NONBLOCK; + +#ifdef O_NOFOLLOW + if (!lp_symlinks(SNUM(conn))) + flags |= O_NOFOLLOW; #endif fd = conn->vfs_ops.open(conn,dos_to_unix(fname,False),flags,mode); @@ -184,7 +184,6 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, fsp->mode = psbuf->st_mode; fsp->inode = psbuf->st_ino; fsp->dev = psbuf->st_dev; - GetTimeOfDay(&fsp->open_time); fsp->vuid = current_user.vuid; fsp->size = psbuf->st_size; fsp->pos = -1; @@ -216,16 +215,6 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), conn->num_files_open + 1)); - /* - * Take care of inherited ACLs on created files. JRA. - */ - - if ((flags & O_CREAT) && (conn->vfs_ops.fchmod_acl != NULL)) { - int saved_errno = errno; /* We might get ENOSYS in the next call.. */ - if (conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode) == -1 && errno == ENOSYS) - errno = saved_errno; /* Ignore ENOSYS */ - } - return True; } @@ -364,7 +353,7 @@ 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 share_mode, +static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, const char *fname, BOOL fcbopen, int *flags) { int deny_mode = GET_DENY_MODE(share_mode); @@ -372,6 +361,14 @@ static int check_share_mode( share_mode_entry *share, int share_mode, int old_deny_mode = GET_DENY_MODE(share->share_mode); /* + * share modes = false means don't bother to check for + * DENY mode conflict. This is a *really* bad idea :-). JRA. + */ + + if(!lp_share_modes(SNUM(conn))) + return True; + + /* * Don't allow any opens once the delete on close flag has been * set. */ @@ -500,7 +497,7 @@ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsi /* Oplock break - unlock to request it. */ unlock_share_entry(conn, dev, inode); - opb_ret = request_oplock_break(share_entry, dev, inode); + opb_ret = request_oplock_break(share_entry); /* Now relock. */ lock_share_entry(conn, dev, inode); @@ -508,7 +505,7 @@ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsi if(opb_ret == False) { DEBUG(0,("open_mode_check: FAILED when breaking oplock (%x) on file %s, \ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode)); - free((char *)old_shares); + SAFE_FREE(old_shares); errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; @@ -526,8 +523,8 @@ 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, share_mode, fname, fcbopen, p_flags) == False) { - free((char *)old_shares); + if(check_share_mode(conn, share_entry, share_mode, fname, fcbopen, p_flags) == False) { + SAFE_FREE(old_shares); errno = EACCES; return -1; } @@ -535,7 +532,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou } /* end for */ if(broke_oplock) { - free((char *)old_shares); + SAFE_FREE(old_shares); num_share_modes = get_share_modes(conn, dev, inode, &old_shares); oplock_contention_count++; @@ -555,11 +552,8 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode)); if (process_exists(broken_entry.pid)) { - pstring errmsg; - slprintf(errmsg, sizeof(errmsg)-1, - "open_mode_check: Existant process %d left active oplock.\n", - broken_entry.pid ); - smb_panic(errmsg); + DEBUG(0,("open_mode_check: Existent process %d left active oplock.\n", + broken_entry.pid )); } if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) { @@ -574,7 +568,7 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn * other process's entry. */ - free((char *)old_shares); + SAFE_FREE(old_shares); num_share_modes = get_share_modes(conn, dev, inode, &old_shares); break; } @@ -583,8 +577,7 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn } while(broke_oplock); - if(old_shares != 0) - free((char *)old_shares); + SAFE_FREE(old_shares); /* * Refuse to grant an oplock in case the contention limit is @@ -629,6 +622,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S 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 delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); BOOL file_existed = VALID_STAT(*psbuf); BOOL fcbopen = False; SMB_DEV_T dev = 0; @@ -645,7 +639,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S of the passed parameters are ignored */ *Access = DOS_OPEN_WRONLY; *action = FILE_WAS_CREATED; - return print_fsp_open(conn); + return print_fsp_open(conn, fname); } fsp = file_new(conn); @@ -688,10 +682,10 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S return NULL; } - if (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST) + if (CAN_WRITE(conn) && (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST)) flags2 |= O_CREAT; - if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE) + if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) flags2 |= O_TRUNC; if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) @@ -916,6 +910,27 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", set_share_mode(fsp, port, oplock_request); + if (delete_on_close) { + NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close); + + if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) { + unlock_share_entry_fsp(fsp); + fd_close(conn,fsp); + file_free(fsp); + return NULL; + } + } + + /* + * Take care of inherited ACLs on created files. JRA. + */ + + if (!file_existed && (conn->vfs_ops.fchmod_acl != NULL)) { + int saved_errno = errno; /* We might get ENOSYS in the next call.. */ + if (conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode) == -1 && errno == ENOSYS) + errno = saved_errno; /* Ignore ENOSYS */ + } + unlock_share_entry_fsp(fsp); conn->num_files_open++; @@ -956,11 +971,9 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, * Setup the files_struct for it. */ - fsp->fd = -1; fsp->mode = psbuf->st_mode; fsp->inode = psbuf->st_ino; fsp->dev = psbuf->st_dev; - GetTimeOfDay(&fsp->open_time); fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; fsp->pos = -1; @@ -985,7 +998,7 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, */ string_set(&fsp->fsp_name,fname); fsp->wbmpx_ptr = NULL; - fsp->wcp = NULL; /* Write cache pointer. */ + fsp->wcp = NULL; /* Write cache pointer. */ conn->num_files_open++; @@ -1040,11 +1053,12 @@ int close_file_fchmod(files_struct *fsp) ****************************************************************************/ files_struct *open_directory(connection_struct *conn, char *fname, - SMB_STRUCT_STAT *psbuf, int smb_ofun, mode_t unixmode, int *action) + SMB_STRUCT_STAT *psbuf, int share_mode, int smb_ofun, mode_t unixmode, int *action) { extern struct current_user current_user; BOOL got_stat = False; files_struct *fsp = file_new(conn); + BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); if(!fsp) return NULL; @@ -1128,18 +1142,16 @@ files_struct *open_directory(connection_struct *conn, char *fname, * Setup the files_struct for it. */ - fsp->fd = -1; fsp->mode = psbuf->st_mode; fsp->inode = psbuf->st_ino; fsp->dev = psbuf->st_dev; - GetTimeOfDay(&fsp->open_time); fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; fsp->pos = -1; fsp->can_lock = True; fsp->can_read = False; fsp->can_write = False; - fsp->share_mode = 0; + fsp->share_mode = share_mode; fsp->print_file = False; fsp->modified = False; fsp->oplock_type = NO_OPLOCK; @@ -1147,6 +1159,16 @@ files_struct *open_directory(connection_struct *conn, char *fname, fsp->is_directory = True; fsp->directory_delete_on_close = False; fsp->conn = conn; + + if (delete_on_close) { + NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close); + + if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) { + file_free(fsp); + return NULL; + } + } + /* * Note that the file name here is the *untranslated* name * ie. it is still in the DOS codepage sent from the client. @@ -1256,12 +1278,12 @@ dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (doub /* Oplock break.... */ unlock_share_entry(conn, dev, inode); - if(request_oplock_break(share_entry, dev, inode) == False) + if(request_oplock_break(share_entry) == False) { DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode)); - free((char *)old_shares); + SAFE_FREE(old_shares); return False; } lock_share_entry(conn, dev, inode); @@ -1291,7 +1313,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou if(broke_oplock) { - free((char *)old_shares); + SAFE_FREE(old_shares); num_share_modes = get_share_modes(conn, dev, inode, &old_shares); } } while(broke_oplock); @@ -1312,7 +1334,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou free_and_exit: unlock_share_entry(conn, dev, inode); - if(old_shares != NULL) - free((char *)old_shares); + SAFE_FREE(old_shares); return(ret); } diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 7033eddc163..cae94bc7a8f 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -1,8 +1,9 @@ /* Unix SMB/Netbios implementation. - Version 1.9. + Version 2.2.x oplock processing Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 1998 - 2001 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,8 +22,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - /* Oplock ipc UDP socket. */ static int oplock_sock = -1; uint16 global_oplock_port = 0; @@ -37,7 +36,7 @@ extern int smb_read_error; static struct kernel_oplocks *koplocks; -static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local); +static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local); /**************************************************************************** Get the number of current exclusive oplocks. @@ -76,97 +75,97 @@ BOOL oplock_message_waiting(fd_set *fds) BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout) { - struct sockaddr_in from; - int fromlen = sizeof(from); - int32 msg_len = 0; - - smb_read_error = 0; - - if(timeout != 0) { - struct timeval to; - int selrtn; - int maxfd = oplock_sock; - - if (koplocks && koplocks->notification_fd != -1) { - FD_SET(koplocks->notification_fd, fds); - maxfd = MAX(maxfd, koplocks->notification_fd); - } - - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; - - selrtn = sys_select(maxfd+1,fds,&to); - - if (selrtn == -1 && errno == EINTR) { - /* could be a kernel oplock interrupt */ - if (koplocks && koplocks->msg_waiting(fds)) { - return koplocks->receive_message(fds, buffer, buffer_len); - } - } - - /* Check if error */ - if(selrtn == -1) { - /* something is wrong. Maybe the socket is dead? */ - smb_read_error = READ_ERROR; - return False; - } - - /* Did we timeout ? */ - if (selrtn == 0) { - smb_read_error = READ_TIMEOUT; - return False; - } - } - - if (koplocks && koplocks->msg_waiting(fds)) { - return koplocks->receive_message(fds, buffer, buffer_len); - } - - if (!FD_ISSET(oplock_sock, fds)) return False; - - /* - * From here down we deal with the smbd <--> smbd - * oplock break protocol only. - */ - - /* - * Read a loopback udp message. - */ - msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN], - buffer_len - OPBRK_CMD_HEADER_LEN, 0, - (struct sockaddr *)&from, &fromlen); - - if(msg_len < 0) { - DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno))); - return False; - } - - /* Validate message length. */ - if(msg_len > (buffer_len - OPBRK_CMD_HEADER_LEN)) { - DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n", - msg_len, - buffer_len - OPBRK_CMD_HEADER_LEN)); - return False; - } - - /* Validate message from address (must be localhost). */ - if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { - DEBUG(0,("receive_local_message: invalid 'from' address \ -(was %lx should be 127.0.0.1\n", (long)from.sin_addr.s_addr)); - return False; - } - - /* Setup the message header */ - SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,msg_len); - SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,ntohs(from.sin_port)); - - return True; + struct sockaddr_in from; + int fromlen = sizeof(from); + int32 msg_len = 0; + + smb_read_error = 0; + + if(timeout != 0) { + struct timeval to; + int selrtn; + int maxfd = oplock_sock; + + if (koplocks && koplocks->notification_fd != -1) { + FD_SET(koplocks->notification_fd, fds); + maxfd = MAX(maxfd, koplocks->notification_fd); + } + + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; + + selrtn = sys_select(maxfd+1,fds,NULL,NULL,&to); + + if (selrtn == -1 && errno == EINTR) { + /* could be a kernel oplock interrupt */ + if (koplocks && koplocks->msg_waiting(fds)) { + return koplocks->receive_message(fds, buffer, buffer_len); + } + } + + /* Check if error */ + if(selrtn == -1) { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return False; + } + + /* Did we timeout ? */ + if (selrtn == 0) { + smb_read_error = READ_TIMEOUT; + return False; + } + } + + if (koplocks && koplocks->msg_waiting(fds)) { + return koplocks->receive_message(fds, buffer, buffer_len); + } + + if (!FD_ISSET(oplock_sock, fds)) + return False; + + /* + * From here down we deal with the smbd <--> smbd + * oplock break protocol only. + */ + + /* + * Read a loopback udp message. + */ + msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN], + buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen); + + if(msg_len < 0) { + DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno))); + return False; + } + + /* Validate message length. */ + if(msg_len > (buffer_len - OPBRK_CMD_HEADER_LEN)) { + DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n", msg_len, + buffer_len - OPBRK_CMD_HEADER_LEN)); + return False; + } + + /* Validate message from address (must be localhost). */ + if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + DEBUG(0,("receive_local_message: invalid 'from' address \ +(was %lx should be 127.0.0.1)\n", (long)from.sin_addr.s_addr)); + return False; + } + + /* Setup the message header */ + SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,msg_len); + SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,ntohs(from.sin_port)); + + return True; } /**************************************************************************** Attempt to set an oplock on a file. Always succeeds if kernel oplocks are disabled (just sets flags). Returns True if oplock set. ****************************************************************************/ + BOOL set_file_oplock(files_struct *fsp, int oplock_type) { if (koplocks && !koplocks->set_oplock(fsp, oplock_type)) @@ -179,8 +178,9 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type) else exclusive_oplocks_open++; - DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n", - fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, + DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, file_id = %lu, \ +tv_sec = %x, tv_usec = %x\n", + fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec )); return True; @@ -192,7 +192,8 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type) void release_file_oplock(files_struct *fsp) { - if (koplocks) koplocks->release_oplock(fsp); + if (koplocks) + koplocks->release_oplock(fsp); if (fsp->oplock_type == LEVEL_II_OPLOCK) level_II_oplocks_open--; @@ -211,7 +212,8 @@ void release_file_oplock(files_struct *fsp) static void downgrade_file_oplock(files_struct *fsp) { - if (koplocks) koplocks->release_oplock(fsp); + if (koplocks) + koplocks->release_oplock(fsp); fsp->oplock_type = LEVEL_II_OPLOCK; exclusive_oplocks_open--; level_II_oplocks_open++; @@ -293,161 +295,142 @@ int setup_oplock_select_set( fd_set *fds) Process an oplock break message - whether it came from the UDP socket or from the kernel. ****************************************************************************/ + BOOL process_local_message(char *buffer, int buf_size) { - int32 msg_len; - uint16 from_port; - char *msg_start; - SMB_DEV_T dev; - SMB_INO_T inode; - pid_t remotepid; - struct timeval tval; - struct timeval *ptval = NULL; - uint16 break_cmd_type; - - msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET); - from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET); - - msg_start = &buffer[OPBRK_CMD_HEADER_LEN]; - - DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n", - msg_len, from_port)); - - /* - * Pull the info out of the requesting packet. - */ - - break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET); - - switch(break_cmd_type) - { - case KERNEL_OPLOCK_BREAK_CMD: - if (!koplocks) { - DEBUG(0,("unexpected kernel oplock break!\n")); - break; - } - if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev)) { - DEBUG(0,("kernel oplock break parse failure!\n")); - } - break; - - case OPLOCK_BREAK_CMD: - case LEVEL_II_OPLOCK_BREAK_CMD: - - /* Ensure that the msg length is correct. */ - if(msg_len != OPLOCK_BREAK_MSG_LEN) - { - DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n", - (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN)); - return False; - } - { - long usec; - time_t sec; - - memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode)); - memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev)); - memcpy((char *)&sec, msg_start+OPLOCK_BREAK_SEC_OFFSET,sizeof(sec)); - tval.tv_sec = sec; - memcpy((char *)&usec, msg_start+OPLOCK_BREAK_USEC_OFFSET, sizeof(usec)); - tval.tv_usec = usec; - - ptval = &tval; - - memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid)); - - DEBUG(5,("process_local_message: (%s) oplock break request from \ -pid %d, port %d, dev = %x, inode = %.0f\n", - (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II", - (int)remotepid, from_port, (unsigned int)dev, (double)inode)); - } - break; - - /* - * Keep this as a debug case - eventually we can remove it. - */ - case 0x8001: - DEBUG(0,("process_local_message: Received unsolicited break \ + int32 msg_len; + uint16 from_port; + char *msg_start; + pid_t remotepid; + SMB_DEV_T dev; + SMB_INO_T inode; + unsigned long file_id; + uint16 break_cmd_type; + + msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET); + from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET); + + msg_start = &buffer[OPBRK_CMD_HEADER_LEN]; + + DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n", + msg_len, from_port)); + + /* + * Pull the info out of the requesting packet. + */ + + break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET); + + switch(break_cmd_type) { + case KERNEL_OPLOCK_BREAK_CMD: + if (!koplocks) { + DEBUG(0,("unexpected kernel oplock break!\n")); + break; + } + if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev, &file_id)) { + DEBUG(0,("kernel oplock break parse failure!\n")); + } + break; + + case OPLOCK_BREAK_CMD: + case LEVEL_II_OPLOCK_BREAK_CMD: + + /* Ensure that the msg length is correct. */ + if(msg_len != OPLOCK_BREAK_MSG_LEN) { + DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n", + (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN)); + return False; + } + + memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid)); + memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode)); + memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev)); + memcpy((char *)&file_id, msg_start+OPLOCK_BREAK_FILEID_OFFSET,sizeof(file_id)); + + DEBUG(5,("process_local_message: (%s) oplock break request from \ +pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n", + (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II", + (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id)); + break; + + /* + * Keep this as a debug case - eventually we can remove it. + */ + case 0x8001: + DEBUG(0,("process_local_message: Received unsolicited break \ reply - dumping info.\n")); - if(msg_len != OPLOCK_BREAK_MSG_LEN) - { - DEBUG(0,("process_local_message: ubr: incorrect length for reply \ + if(msg_len != OPLOCK_BREAK_MSG_LEN) { + DEBUG(0,("process_local_message: ubr: incorrect length for reply \ (was %d, should be %d).\n", (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN)); - return False; - } - - { - memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode)); - memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid)); - memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev)); - - DEBUG(0,("process_local_message: unsolicited oplock break reply from \ -pid %d, port %d, dev = %x, inode = %.0f\n", (int)remotepid, from_port, (unsigned int)dev, (double)inode)); - - } - return False; - - default: - DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n", - (unsigned int)SVAL(msg_start,0))); - return False; - } - - /* - * Now actually process the break request. - */ - - if((exclusive_oplocks_open + level_II_oplocks_open) != 0) - { - if (oplock_break(dev, inode, ptval, False) == False) - { - DEBUG(0,("process_local_message: oplock break failed.\n")); - return False; - } - } - else - { - /* - * If we have no record of any currently open oplocks, - * it's not an error, as a close command may have - * just been issued on the file that was oplocked. - * Just log a message and return success in this case. - */ - DEBUG(3,("process_local_message: oplock break requested with no outstanding \ + return False; + } + + memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode)); + memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid)); + memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev)); + memcpy((char *)&file_id, msg_start+OPLOCK_BREAK_FILEID_OFFSET,sizeof(file_id)); + + DEBUG(0,("process_local_message: unsolicited oplock break reply from \ +pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n", + (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id)); + + return False; + + default: + DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n", + (unsigned int)SVAL(msg_start,0))); + return False; + } + + /* + * Now actually process the break request. + */ + + if((exclusive_oplocks_open + level_II_oplocks_open) != 0) { + if (oplock_break(dev, inode, file_id, False) == False) { + DEBUG(0,("process_local_message: oplock break failed.\n")); + return False; + } + } else { + /* + * If we have no record of any currently open oplocks, + * it's not an error, as a close command may have + * just been issued on the file that was oplocked. + * Just log a message and return success in this case. + */ + DEBUG(3,("process_local_message: oplock break requested with no outstanding \ oplocks. Returning success.\n")); - } - - /* - * Do the appropriate reply - none in the kernel or level II case. - */ - - if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD) - { - struct sockaddr_in toaddr; - - /* Send the message back after OR'ing in the 'REPLY' bit. */ - SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY); - - memset((char *)&toaddr,'\0',sizeof(toaddr)); - toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - toaddr.sin_port = htons(from_port); - toaddr.sin_family = AF_INET; - - if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, - (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) - { - DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n", - (int)remotepid, strerror(errno))); - return False; - } - - DEBUG(5,("process_local_message: oplock break reply sent to \ -pid %d, port %d, for file dev = %x, inode = %.0f\n", - (int)remotepid, from_port, (unsigned int)dev, (double)inode)); - } - - return True; + } + + /* + * Do the appropriate reply - none in the kernel or level II case. + */ + + if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD) { + struct sockaddr_in toaddr; + + /* Send the message back after OR'ing in the 'REPLY' bit. */ + SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY); + + memset((char *)&toaddr,'\0',sizeof(toaddr)); + toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + toaddr.sin_port = htons(from_port); + toaddr.sin_family = AF_INET; + + if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, + (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) { + DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n", + (int)remotepid, strerror(errno))); + return False; + } + + DEBUG(5,("process_local_message: oplock break reply sent to \ +pid %d, port %d, for file dev = %x, inode = %.0f, file_id = %lu\n", + (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id)); + } + + return True; } /**************************************************************************** @@ -476,81 +459,82 @@ static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2) static void wait_before_sending_break(BOOL local_request) { - extern struct timeval smb_last_time; + extern struct timeval smb_last_time; - if(local_request) { - struct timeval cur_tv; - long wait_left = (long)lp_oplock_break_wait_time(); + if(local_request) { + struct timeval cur_tv; + long wait_left = (long)lp_oplock_break_wait_time(); - if (wait_left == 0) - return; + if (wait_left == 0) + return; - GetTimeOfDay(&cur_tv); + GetTimeOfDay(&cur_tv); - wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) + + wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) + ((cur_tv.tv_usec - smb_last_time.tv_usec)/1000); - if(wait_left > 0) { - wait_left = MIN(wait_left, 1000); - sys_usleep(wait_left * 1000); - } - } + if(wait_left > 0) { + wait_left = MIN(wait_left, 1000); + sys_usleep(wait_left * 1000); + } + } } /**************************************************************************** Ensure that we have a valid oplock. ****************************************************************************/ -static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval) + +static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id) { - files_struct *fsp = NULL; - - if( DEBUGLVL( 3 ) ) - { - dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f tv_sec = %x, tv_usec = %x.\n", - (unsigned int)dev, (double)inode, tval ? (int)tval->tv_sec : 0, - tval ? (int)tval->tv_usec : 0); - dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n", - exclusive_oplocks_open, level_II_oplocks_open ); - } - - /* We need to search the file open table for the - entry containing this dev and inode, and ensure - we have an oplock on it. */ - fsp = file_find_dit(dev, inode, tval); - - if(fsp == NULL) - { - /* The file could have been closed in the meantime - return success. */ - if( DEBUGLVL( 3 ) ) - { - dbgtext( "initial_break_processing: cannot find open file with " ); - dbgtext( "dev = %x, inode = %.0f ", (unsigned int)dev, (double)inode); - dbgtext( "allowing break to succeed.\n" ); - } - return NULL; - } - - /* Ensure we have an oplock on the file */ - - /* There is a potential race condition in that an oplock could - have been broken due to another udp request, and yet there are - still oplock break messages being sent in the udp message - queue for this file. So return true if we don't have an oplock, - as we may have just freed it. - */ - - if(fsp->oplock_type == NO_OPLOCK) - { - if( DEBUGLVL( 3 ) ) - { - dbgtext( "initial_break_processing: file %s ", fsp->fsp_name ); - dbgtext( "(dev = %x, inode = %.0f) has no oplock.\n", (unsigned int)dev, (double)inode ); - dbgtext( "Allowing break to succeed regardless.\n" ); - } - return NULL; - } - - return fsp; + files_struct *fsp = NULL; + + if( DEBUGLVL( 3 ) ) { + dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f file_id = %lu\n", + (unsigned int)dev, (double)inode, file_id); + dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n", + exclusive_oplocks_open, level_II_oplocks_open ); + } + + /* + * We need to search the file open table for the + * entry containing this dev and inode, and ensure + * we have an oplock on it. + */ + + fsp = file_find_dif(dev, inode, file_id); + + if(fsp == NULL) { + /* The file could have been closed in the meantime - return success. */ + if( DEBUGLVL( 3 ) ) { + dbgtext( "initial_break_processing: cannot find open file with " ); + dbgtext( "dev = %x, inode = %.0f file_id = %lu", (unsigned int)dev, + (double)inode, file_id); + dbgtext( "allowing break to succeed.\n" ); + } + return NULL; + } + + /* Ensure we have an oplock on the file */ + + /* + * There is a potential race condition in that an oplock could + * have been broken due to another udp request, and yet there are + * still oplock break messages being sent in the udp message + * queue for this file. So return true if we don't have an oplock, + * as we may have just freed it. + */ + + if(fsp->oplock_type == NO_OPLOCK) { + if( DEBUGLVL( 3 ) ) { + dbgtext( "initial_break_processing: file %s ", fsp->fsp_name ); + dbgtext( "(dev = %x, inode = %.0f, file_id = %lu) has no oplock.\n", + (unsigned int)dev, (double)inode, fsp->file_id ); + dbgtext( "Allowing break to succeed regardless.\n" ); + } + return NULL; + } + + return fsp; } /**************************************************************************** @@ -559,336 +543,322 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, st BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token) { - extern uint32 global_client_caps; - char outbuf[128]; - BOOL got_lock = False; - SMB_DEV_T dev = fsp->dev; - SMB_INO_T inode = fsp->inode; - - /* - * We can have a level II oplock even if the client is not - * level II oplock aware. In this case just remove the - * flags and don't send the break-to-none message to - * the client. - */ - - if (global_client_caps & CAP_LEVEL_II_OPLOCKS) { - /* - * If we are sending an oplock break due to an SMB sent - * by our own client we ensure that we wait at leat - * lp_oplock_break_wait_time() milliseconds before sending - * the packet. Sending the packet sooner can break Win9x - * and has reported to cause problems on NT. JRA. - */ - - wait_before_sending_break(local_request); - - /* Prepare the SMBlockingX message. */ - - prepare_break_message( outbuf, fsp, False); - if (!send_smb(smbd_server_fd(), outbuf)) - exit_server("oplock_break_level2: send_smb failed.\n"); - } - - /* - * Now we must update the shared memory structure to tell - * everyone else we no longer have a level II oplock on - * this open file. If local_request is true then token is - * the existing lock on the shared memory area. - */ - - if(!local_request && lock_share_entry_fsp(fsp) == False) { - DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name )); - } else { - got_lock = True; - } - - if(remove_share_oplock(fsp)==False) { - DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name )); - } - - if (!local_request && got_lock) - unlock_share_entry_fsp(fsp); - - fsp->oplock_type = NO_OPLOCK; - level_II_oplocks_open--; - - if(level_II_oplocks_open < 0) - { - DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n", - level_II_oplocks_open)); - abort(); - } - - if( DEBUGLVL( 3 ) ) - { - dbgtext( "oplock_break_level2: returning success for " ); - dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ); - dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open ); - } - - return True; + extern uint32 global_client_caps; + char outbuf[128]; + BOOL got_lock = False; + SMB_DEV_T dev = fsp->dev; + SMB_INO_T inode = fsp->inode; + + /* + * We can have a level II oplock even if the client is not + * level II oplock aware. In this case just remove the + * flags and don't send the break-to-none message to + * the client. + */ + + if (global_client_caps & CAP_LEVEL_II_OPLOCKS) { + /* + * If we are sending an oplock break due to an SMB sent + * by our own client we ensure that we wait at leat + * lp_oplock_break_wait_time() milliseconds before sending + * the packet. Sending the packet sooner can break Win9x + * and has reported to cause problems on NT. JRA. + */ + + wait_before_sending_break(local_request); + + /* Prepare the SMBlockingX message. */ + + prepare_break_message( outbuf, fsp, False); + if (!send_smb(smbd_server_fd(), outbuf)) + exit_server("oplock_break_level2: send_smb failed.\n"); + } + + /* + * Now we must update the shared memory structure to tell + * everyone else we no longer have a level II oplock on + * this open file. If local_request is true then token is + * the existing lock on the shared memory area. + */ + + if(!local_request && lock_share_entry_fsp(fsp) == False) { + DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name )); + } else { + got_lock = True; + } + + if(remove_share_oplock(fsp)==False) { + DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name )); + } + + if (!local_request && got_lock) + unlock_share_entry_fsp(fsp); + + fsp->oplock_type = NO_OPLOCK; + level_II_oplocks_open--; + + if(level_II_oplocks_open < 0) { + DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n", + level_II_oplocks_open)); + abort(); + } + + if( DEBUGLVL( 3 ) ) { + dbgtext( "oplock_break_level2: returning success for " ); + dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, fsp->file_id ); + dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open ); + } + + return True; } /**************************************************************************** Process an oplock break directly. ****************************************************************************/ -static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local_request) +static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local_request) { - extern uint32 global_client_caps; - extern struct current_user current_user; - char *inbuf = NULL; - char *outbuf = NULL; - files_struct *fsp = NULL; - time_t start_time; - BOOL shutdown_server = False; - BOOL oplock_timeout = False; - connection_struct *saved_user_conn; - connection_struct *saved_fsp_conn; - int saved_vuid; - pstring saved_dir; - int timeout = (OPLOCK_BREAK_TIMEOUT * 1000); - pstring file_name; - BOOL using_levelII; - - if((fsp = initial_break_processing(dev, inode, tval)) == NULL) - return True; - - /* - * Deal with a level II oplock going break to none separately. - */ - - if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) - return oplock_break_level2(fsp, local_request, -1); - - /* Mark the oplock break as sent - we don't want to send twice! */ - if (fsp->sent_oplock_break) - { - if( DEBUGLVL( 0 ) ) - { - dbgtext( "oplock_break: ERROR: oplock_break already sent for " ); - dbgtext( "file %s ", fsp->fsp_name); - dbgtext( "(dev = %x, inode = %.0f)\n", (unsigned int)dev, (double)inode ); - } - - /* We have to fail the open here as we cannot send another oplock break on - this file whilst we are awaiting a response from the client - neither - can we allow another open to succeed while we are waiting for the - client. - */ - return False; - } - - if(global_oplock_break) { - DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n")); - abort(); - } - - /* Now comes the horrid part. We must send an oplock break to the client, - and then process incoming messages until we get a close or oplock release. - At this point we know we need a new inbuf/outbuf buffer pair. - We cannot use these staticaly as we may recurse into here due to - messages crossing on the wire. - */ - - if((inbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) - { - DEBUG(0,("oplock_break: malloc fail for input buffer.\n")); - return False; - } - - if((outbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) - { - DEBUG(0,("oplock_break: malloc fail for output buffer.\n")); - free(inbuf); - inbuf = NULL; - return False; - } - - /* - * If we are sending an oplock break due to an SMB sent - * by our own client we ensure that we wait at leat - * lp_oplock_break_wait_time() milliseconds before sending - * the packet. Sending the packet sooner can break Win9x - * and has reported to cause problems on NT. JRA. - */ - - wait_before_sending_break(local_request); - - /* Prepare the SMBlockingX message. */ - - if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && - !koplocks && /* NOTE: we force levelII off for kernel oplocks - - this will change when it is supported */ - lp_level2_oplocks(SNUM(fsp->conn))) { - using_levelII = True; - } else { - using_levelII = False; - } - - prepare_break_message( outbuf, fsp, using_levelII); - /* Remember if we just sent a break to level II on this file. */ - fsp->sent_oplock_break = using_levelII? - LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT; - - if (!send_smb(smbd_server_fd(), outbuf)) - exit_server("oplock_break: send_smb failed.\n"); - - /* We need this in case a readraw crosses on the wire. */ - global_oplock_break = True; + extern uint32 global_client_caps; + extern struct current_user current_user; + char *inbuf = NULL; + char *outbuf = NULL; + files_struct *fsp = NULL; + time_t start_time; + BOOL shutdown_server = False; + BOOL oplock_timeout = False; + connection_struct *saved_user_conn; + connection_struct *saved_fsp_conn; + int saved_vuid; + pstring saved_dir; + int timeout = (OPLOCK_BREAK_TIMEOUT * 1000); + pstring file_name; + BOOL using_levelII; + + if((fsp = initial_break_processing(dev, inode, file_id)) == NULL) + return True; + + /* + * Deal with a level II oplock going break to none separately. + */ + + if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) + return oplock_break_level2(fsp, local_request, -1); + + /* Mark the oplock break as sent - we don't want to send twice! */ + if (fsp->sent_oplock_break) { + if( DEBUGLVL( 0 ) ) { + dbgtext( "oplock_break: ERROR: oplock_break already sent for " ); + dbgtext( "file %s ", fsp->fsp_name); + dbgtext( "(dev = %x, inode = %.0f, file_id = %lu)\n", (unsigned int)dev, (double)inode, fsp->file_id ); + } + + /* + * We have to fail the open here as we cannot send another oplock break on + * this file whilst we are awaiting a response from the client - neither + * can we allow another open to succeed while we are waiting for the client. + */ + return False; + } + + if(global_oplock_break) { + DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n")); + abort(); + } + + /* + * Now comes the horrid part. We must send an oplock break to the client, + * and then process incoming messages until we get a close or oplock release. + * At this point we know we need a new inbuf/outbuf buffer pair. + * We cannot use these staticaly as we may recurse into here due to + * messages crossing on the wire. + */ + + if((inbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) { + DEBUG(0,("oplock_break: malloc fail for input buffer.\n")); + return False; + } + + if((outbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) { + DEBUG(0,("oplock_break: malloc fail for output buffer.\n")); + SAFE_FREE(inbuf); + return False; + } + + /* + * If we are sending an oplock break due to an SMB sent + * by our own client we ensure that we wait at leat + * lp_oplock_break_wait_time() milliseconds before sending + * the packet. Sending the packet sooner can break Win9x + * and has reported to cause problems on NT. JRA. + */ + + wait_before_sending_break(local_request); + + /* Prepare the SMBlockingX message. */ + + if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && + !koplocks && /* NOTE: we force levelII off for kernel oplocks - this will change when it is supported */ + lp_level2_oplocks(SNUM(fsp->conn))) { + using_levelII = True; + } else { + using_levelII = False; + } + + prepare_break_message( outbuf, fsp, using_levelII); + /* Remember if we just sent a break to level II on this file. */ + fsp->sent_oplock_break = using_levelII? LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT; + + if (!send_smb(smbd_server_fd(), outbuf)) + exit_server("oplock_break: send_smb failed.\n"); + + /* We need this in case a readraw crosses on the wire. */ + global_oplock_break = True; - /* Process incoming messages. */ - - /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT - seconds we should just die.... */ - - start_time = time(NULL); - - /* - * Save the information we need to re-become the - * user, then unbecome the user whilst we're doing this. - */ - saved_user_conn = current_user.conn; - saved_vuid = current_user.vuid; - saved_fsp_conn = fsp->conn; - vfs_GetWd(saved_fsp_conn,saved_dir); - unbecome_user(); - /* Save the chain fnum. */ - file_chain_save(); - - /* - * From Charles Hoch <hoch@exemplary.com>. If the break processing - * code closes the file (as it often does), then the fsp pointer here - * points to free()'d memory. We *must* revalidate fsp each time - * around the loop. - */ - - pstrcpy(file_name, fsp->fsp_name); - - while((fsp = initial_break_processing(dev, inode, tval)) && - OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - { - if(receive_smb(smbd_server_fd(),inbuf, timeout) == False) - { - /* - * Die if we got an error. - */ - - if (smb_read_error == READ_EOF) { - DEBUG( 0, ( "oplock_break: end of file from client\n" ) ); - shutdown_server = True; - } else if (smb_read_error == READ_ERROR) { - DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) ); - shutdown_server = True; - } else if (smb_read_error == READ_TIMEOUT) { - DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n", - OPLOCK_BREAK_TIMEOUT ) ); - oplock_timeout = True; - } - - DEBUGADD( 0, ( "oplock_break failed for file %s ", file_name ) ); - DEBUGADD( 0, ( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode)); - - break; - } - - /* - * There are certain SMB requests that we shouldn't allow - * to recurse. opens, renames and deletes are the obvious - * ones. This is handled in the switch_message() function. - * If global_oplock_break is set they will push the packet onto - * the pending smb queue and return -1 (no reply). - * JRA. - */ - - process_smb(inbuf, outbuf); - - /* - * Die if we go over the time limit. - */ - - if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT) - { - if( DEBUGLVL( 0 ) ) - { - dbgtext( "oplock_break: no break received from client " ); - dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT ); - dbgtext( "oplock_break failed for file %s ", fsp->fsp_name ); - dbgtext( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode ); - } - oplock_timeout = True; - break; - } - } - - /* - * Go back to being the user who requested the oplock - * break. - */ - if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !become_user(saved_user_conn, saved_vuid)) - { - DEBUG( 0, ( "oplock_break: unable to re-become user!" ) ); - DEBUGADD( 0, ( "Shutting down server\n" ) ); - close(oplock_sock); - exit_server("unable to re-become user"); - } - /* Including the directory. */ - vfs_ChDir(saved_fsp_conn,saved_dir); - - /* Restore the chain fnum. */ - file_chain_restore(); - - /* Free the buffers we've been using to recurse. */ - free(inbuf); - free(outbuf); - - /* We need this in case a readraw crossed on the wire. */ - if(global_oplock_break) - global_oplock_break = False; - - /* - * If the client timed out then clear the oplock (or go to level II) - * and continue. This seems to be what NT does and is better than dropping - * the connection. - */ - - if(oplock_timeout && (fsp = initial_break_processing(dev, inode, tval)) && - OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - { - DEBUG(0,("oplock_break: client failure in oplock break in file %s\n", fsp->fsp_name)); - remove_oplock(fsp,True); - global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */ - } - - /* - * If the client had an error we must die. - */ - - if(shutdown_server) - { - DEBUG( 0, ( "oplock_break: client failure in break - " ) ); - DEBUGADD( 0, ( "shutting down this smbd.\n" ) ); - close(oplock_sock); - exit_server("oplock break failure"); - } - - /* Santity check - remove this later. JRA */ - if(exclusive_oplocks_open < 0) - { - DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n", - exclusive_oplocks_open)); - abort(); - } - - if( DEBUGLVL( 3 ) ) - { - dbgtext( "oplock_break: returning success for " ); - dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ); - dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open ); - } - - return True; + /* Process incoming messages. */ + + /* + * JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT + * seconds we should just die.... + */ + + start_time = time(NULL); + + /* + * Save the information we need to re-become the + * user, then unbecome the user whilst we're doing this. + */ + saved_user_conn = current_user.conn; + saved_vuid = current_user.vuid; + saved_fsp_conn = fsp->conn; + vfs_GetWd(saved_fsp_conn,saved_dir); + change_to_root_user(); + /* Save the chain fnum. */ + file_chain_save(); + + /* + * From Charles Hoch <hoch@exemplary.com>. If the break processing + * code closes the file (as it often does), then the fsp pointer here + * points to free()'d memory. We *must* revalidate fsp each time + * around the loop. + */ + + pstrcpy(file_name, fsp->fsp_name); + + while((fsp = initial_break_processing(dev, inode, file_id)) && + OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { + if(receive_smb(smbd_server_fd(),inbuf, timeout) == False) { + /* + * Die if we got an error. + */ + + if (smb_read_error == READ_EOF) { + DEBUG( 0, ( "oplock_break: end of file from client\n" ) ); + shutdown_server = True; + } else if (smb_read_error == READ_ERROR) { + DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) ); + shutdown_server = True; + } else if (smb_read_error == READ_TIMEOUT) { + DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n", OPLOCK_BREAK_TIMEOUT ) ); + oplock_timeout = True; + } + + DEBUGADD( 0, ( "oplock_break failed for file %s ", file_name ) ); + DEBUGADD( 0, ( "(dev = %x, inode = %.0f, file_id = %lu).\n", + (unsigned int)dev, (double)inode, file_id)); + + break; + } + + /* + * There are certain SMB requests that we shouldn't allow + * to recurse. opens, renames and deletes are the obvious + * ones. This is handled in the switch_message() function. + * If global_oplock_break is set they will push the packet onto + * the pending smb queue and return -1 (no reply). + * JRA. + */ + + process_smb(inbuf, outbuf); + + /* + * Die if we go over the time limit. + */ + + if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT) { + if( DEBUGLVL( 0 ) ) { + dbgtext( "oplock_break: no break received from client " ); + dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT ); + dbgtext( "oplock_break failed for file %s ", fsp->fsp_name ); + dbgtext( "(dev = %x, inode = %.0f, file_id = %lu).\n", + (unsigned int)dev, (double)inode, file_id ); + } + oplock_timeout = True; + break; + } + } + + /* + * Go back to being the user who requested the oplock + * break. + */ + if((saved_user_conn != NULL) && (saved_vuid != UID_FIELD_INVALID) && !change_to_user(saved_user_conn, saved_vuid)) { + DEBUG( 0, ( "oplock_break: unable to re-become user!" ) ); + DEBUGADD( 0, ( "Shutting down server\n" ) ); + close(oplock_sock); + exit_server("unable to re-become user"); + } + + /* Including the directory. */ + vfs_ChDir(saved_fsp_conn,saved_dir); + + /* Restore the chain fnum. */ + file_chain_restore(); + + /* Free the buffers we've been using to recurse. */ + SAFE_FREE(inbuf); + SAFE_FREE(outbuf); + + /* We need this in case a readraw crossed on the wire. */ + if(global_oplock_break) + global_oplock_break = False; + + /* + * If the client timed out then clear the oplock (or go to level II) + * and continue. This seems to be what NT does and is better than dropping + * the connection. + */ + + if(oplock_timeout && (fsp = initial_break_processing(dev, inode, file_id)) && + OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { + DEBUG(0,("oplock_break: client failure in oplock break in file %s\n", fsp->fsp_name)); + remove_oplock(fsp,True); + global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */ + } + + /* + * If the client had an error we must die. + */ + + if(shutdown_server) { + DEBUG( 0, ( "oplock_break: client failure in break - " ) ); + DEBUGADD( 0, ( "shutting down this smbd.\n" ) ); + close(oplock_sock); + exit_server("oplock break failure"); + } + + /* Santity check - remove this later. JRA */ + if(exclusive_oplocks_open < 0) { + DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n", exclusive_oplocks_open)); + abort(); + } + + if( DEBUGLVL( 3 ) ) { + dbgtext( "oplock_break: returning success for " ); + dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, file_id ); + dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open ); + } + + return True; } /**************************************************************************** @@ -896,212 +866,187 @@ Send an oplock break message to another smbd process. If the oplock is held by the local smbd then call the oplock break function directly. ****************************************************************************/ -BOOL request_oplock_break(share_mode_entry *share_entry, - SMB_DEV_T dev, SMB_INO_T inode) +BOOL request_oplock_break(share_mode_entry *share_entry) { - char op_break_msg[OPLOCK_BREAK_MSG_LEN]; - struct sockaddr_in addr_out; - pid_t pid = sys_getpid(); - time_t start_time; - int time_left; - long usec; - time_t sec; - - if(pid == share_entry->pid) - { - /* We are breaking our own oplock, make sure it's us. */ - if(share_entry->op_port != global_oplock_port) - { - DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \ + char op_break_msg[OPLOCK_BREAK_MSG_LEN]; + struct sockaddr_in addr_out; + pid_t pid = sys_getpid(); + time_t start_time; + int time_left; + SMB_DEV_T dev = share_entry->dev; + SMB_INO_T inode = share_entry->inode; + unsigned long file_id = share_entry->share_file_id; + + if(pid == share_entry->pid) { + /* We are breaking our own oplock, make sure it's us. */ + if(share_entry->op_port != global_oplock_port) { + DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port)); - return False; - } + return False; + } - DEBUG(5,("request_oplock_break: breaking our own oplock\n")); + DEBUG(5,("request_oplock_break: breaking our own oplock\n")); #if 1 /* JRA PARANOIA TEST.... */ - { - files_struct *fsp = file_find_dit(dev, inode, &share_entry->time); - if (!fsp) { - DEBUG(0,("request_oplock_break: PANIC : breaking our own oplock requested for \ -dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x and no fsp found !\n", - (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec, - (int)share_entry->time.tv_usec )); - smb_panic("request_oplock_break: no fsp found for our own oplock\n"); - } - } + { + files_struct *fsp = file_find_dif(dev, inode, file_id); + if (!fsp) { + DEBUG(0,("request_oplock_break: PANIC : breaking our own oplock requested for \ +dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", + (unsigned int)dev, (double)inode, file_id )); + smb_panic("request_oplock_break: no fsp found for our own oplock\n"); + } + } #endif /* END JRA PARANOIA TEST... */ - /* Call oplock break direct. */ - return oplock_break(dev, inode, &share_entry->time, True); - } - - /* We need to send a OPLOCK_BREAK_CMD message to the - port in the share mode entry. */ - - if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { - SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD); - } else { - SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD); - } - memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid)); - sec = (time_t)share_entry->time.tv_sec; - memcpy(op_break_msg+OPLOCK_BREAK_SEC_OFFSET,(char *)&sec,sizeof(sec)); - usec = (long)share_entry->time.tv_usec; - memcpy(op_break_msg+OPLOCK_BREAK_USEC_OFFSET,(char *)&usec,sizeof(usec)); - memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev)); - memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode)); - - /* set the address and port */ - memset((char *)&addr_out,'\0',sizeof(addr_out)); - addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr_out.sin_port = htons( share_entry->op_port ); - addr_out.sin_family = AF_INET; + /* Call oplock break direct. */ + return oplock_break(dev, inode, file_id, True); + } + + /* We need to send a OPLOCK_BREAK_CMD message to the port in the share mode entry. */ + + if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { + SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD); + } else { + SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD); + } + + memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid)); + memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev)); + memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode)); + memcpy(op_break_msg+OPLOCK_BREAK_FILEID_OFFSET,(char *)&file_id,sizeof(file_id)); + + /* Set the address and port. */ + memset((char *)&addr_out,'\0',sizeof(addr_out)); + addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr_out.sin_port = htons( share_entry->op_port ); + addr_out.sin_family = AF_INET; - if( DEBUGLVL( 3 ) ) - { - dbgtext( "request_oplock_break: sending a oplock break message to " ); - dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port ); - dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n", - (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec, - (int)share_entry->time.tv_usec ); - - } - - if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0, - (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) - { - if( DEBUGLVL( 0 ) ) - { - dbgtext( "request_oplock_break: failed when sending a oplock " ); - dbgtext( "break message to pid %d ", (int)share_entry->pid ); - dbgtext( "on port %d ", share_entry->op_port ); - dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n", - (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec, - (int)share_entry->time.tv_usec ); - dbgtext( "Error was %s\n", strerror(errno) ); - } - return False; - } - - /* - * If we just sent a message to a level II oplock share entry then - * we are done and may return. - */ - - if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { - DEBUG(3,("request_oplock_break: sent break message to level II entry.\n")); - return True; - } - - /* - * Now we must await the oplock broken message coming back - * from the target smbd process. Timeout if it fails to - * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds. - * While we get messages that aren't ours, loop. - */ - - start_time = time(NULL); - time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR; - - while(time_left >= 0) - { - char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN]; - uint16 reply_from_port; - char *reply_msg_start; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(oplock_sock,&fds); - - if (koplocks && koplocks->notification_fd != -1) { - FD_SET(koplocks->notification_fd, &fds); - } - - if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply), - time_left ? time_left * 1000 : 1) == False) - { - if(smb_read_error == READ_TIMEOUT) - { - if( DEBUGLVL( 0 ) ) - { - dbgtext( "request_oplock_break: no response received to oplock " ); - dbgtext( "break request to pid %d ", (int)share_entry->pid ); - dbgtext( "on port %d ", share_entry->op_port ); - dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ); - dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n", - (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec, - (int)share_entry->time.tv_usec ); - } - - /* - * This is a hack to make handling of failing clients more robust. - * If a oplock break response message is not received in the timeout - * period we may assume that the smbd servicing that client holding - * the oplock has died and the client changes were lost anyway, so - * we should continue to try and open the file. - */ - break; - } - else - if( DEBUGLVL( 0 ) ) - { - dbgtext( "request_oplock_break: error in response received " ); - dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid ); - dbgtext( "on port %d ", share_entry->op_port ); - dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n", - (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec, - (int)share_entry->time.tv_usec ); - dbgtext( "Error was (%s).\n", strerror(errno) ); - } - return False; - } - - reply_from_port = SVAL(op_break_reply,OPBRK_CMD_PORT_OFFSET); - - reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN]; - - - /* - * Test to see if this is the reply we are awaiting. - */ - if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) && - ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) && - (reply_from_port == share_entry->op_port) && - (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], - &op_break_msg[OPLOCK_BREAK_PID_OFFSET], - OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0)) - { - /* - * This is the reply we've been waiting for. - */ - break; - } - else - { - /* - * This is another message - a break request. - * Note that both kernel oplock break requests - * and UDP inter-smbd oplock break requests will - * be processed here. - * - * Process it to prevent potential deadlock. - * Note that the code in switch_message() prevents - * us from recursing into here as any SMB requests - * we might process that would cause another oplock - * break request to be made will be queued. - * JRA. - */ - - process_local_message(op_break_reply, sizeof(op_break_reply)); - } - - time_left -= (time(NULL) - start_time); - } - - DEBUG(3,("request_oplock_break: broke oplock.\n")); - - return True; + if( DEBUGLVL( 3 ) ) { + dbgtext( "request_oplock_break: sending a oplock break message to " ); + dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port ); + dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n", + (unsigned int)dev, (double)inode, file_id ); + } + + if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0, + (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) { + if( DEBUGLVL( 0 ) ) { + dbgtext( "request_oplock_break: failed when sending a oplock " ); + dbgtext( "break message to pid %d ", (int)share_entry->pid ); + dbgtext( "on port %d ", share_entry->op_port ); + dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n", + (unsigned int)dev, (double)inode, file_id ); + dbgtext( "Error was %s\n", strerror(errno) ); + } + return False; + } + + /* + * If we just sent a message to a level II oplock share entry then + * we are done and may return. + */ + + if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { + DEBUG(3,("request_oplock_break: sent break message to level II entry.\n")); + return True; + } + + /* + * Now we must await the oplock broken message coming back + * from the target smbd process. Timeout if it fails to + * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds. + * While we get messages that aren't ours, loop. + */ + + start_time = time(NULL); + time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR; + + while(time_left >= 0) { + char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN]; + uint16 reply_from_port; + char *reply_msg_start; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(oplock_sock,&fds); + + if (koplocks && koplocks->notification_fd != -1) { + FD_SET(koplocks->notification_fd, &fds); + } + + if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply), + time_left ? time_left * 1000 : 1) == False) { + if(smb_read_error == READ_TIMEOUT) { + if( DEBUGLVL( 0 ) ) { + dbgtext( "request_oplock_break: no response received to oplock " ); + dbgtext( "break request to pid %d ", (int)share_entry->pid ); + dbgtext( "on port %d ", share_entry->op_port ); + dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n", + (unsigned int)dev, (double)inode, file_id ); + } + + /* + * This is a hack to make handling of failing clients more robust. + * If a oplock break response message is not received in the timeout + * period we may assume that the smbd servicing that client holding + * the oplock has died and the client changes were lost anyway, so + * we should continue to try and open the file. + */ + break; + } else { + if( DEBUGLVL( 0 ) ) { + dbgtext( "request_oplock_break: error in response received " ); + dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid ); + dbgtext( "on port %d ", share_entry->op_port ); + dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n", + (unsigned int)dev, (double)inode, file_id ); + dbgtext( "Error was (%s).\n", strerror(errno) ); + } + } + return False; + } + + reply_from_port = SVAL(op_break_reply,OPBRK_CMD_PORT_OFFSET); + reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN]; + + /* + * Test to see if this is the reply we are awaiting. + */ + if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) && + ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) && + (reply_from_port == share_entry->op_port) && + (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], &op_break_msg[OPLOCK_BREAK_PID_OFFSET], + OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0)) { + + /* + * This is the reply we've been waiting for. + */ + break; + } else { + /* + * This is another message - a break request. + * Note that both kernel oplock break requests + * and UDP inter-smbd oplock break requests will + * be processed here. + * + * Process it to prevent potential deadlock. + * Note that the code in switch_message() prevents + * us from recursing into here as any SMB requests + * we might process that would cause another oplock + * break request to be made will be queued. + * JRA. + */ + + process_local_message(op_break_reply, sizeof(op_break_reply)); + } + + time_left -= (time(NULL) - start_time); + } + + DEBUG(3,("request_oplock_break: broke oplock.\n")); + + return True; } /**************************************************************************** @@ -1111,20 +1056,20 @@ dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x and no fsp found !\n", Used as a last ditch attempt to free a space in the file table when we have run out. ****************************************************************************/ + BOOL attempt_close_oplocked_file(files_struct *fsp) { + DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name)); - DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name)); - - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd != -1)) { - /* Try and break the oplock. */ - if (oplock_break(fsp->dev, fsp->inode, &fsp->open_time, True)) { - if(file_find_fsp(fsp) == NULL) /* Did the oplock break close the file ? */ - return True; - } - } + if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd != -1)) { + /* Try and break the oplock. */ + if (oplock_break(fsp->dev, fsp->inode, fsp->file_id, True)) { + if(file_find_fsp(fsp) == NULL) /* Did the oplock break close the file ? */ + return True; + } + } - return False; + return False; } /**************************************************************************** @@ -1192,7 +1137,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp) */ if (pid == share_entry->pid) { - files_struct *new_fsp = file_find_dit(fsp->dev, fsp->inode, &share_entry->time); + files_struct *new_fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id); /* Paranoia check... */ if(new_fsp == NULL) { @@ -1213,12 +1158,11 @@ void release_level_2_oplocks_on_change(files_struct *fsp) */ DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock.\n")); - request_oplock_break(share_entry, fsp->dev, fsp->inode); + request_oplock_break(share_entry); } } - if (share_list) - free((char *)share_list); + SAFE_FREE(share_list); unlock_share_entry_fsp(fsp); /* Paranoia check... */ @@ -1231,6 +1175,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp) /**************************************************************************** setup oplocks for this process ****************************************************************************/ + BOOL init_oplocks(void) { struct sockaddr_in sock_name; diff --git a/source/smbd/oplock_irix.c b/source/smbd/oplock_irix.c index faf7e8e3c87..10520461753 100644 --- a/source/smbd/oplock_irix.c +++ b/source/smbd/oplock_irix.c @@ -22,14 +22,14 @@ #include "includes.h" #if HAVE_KERNEL_OPLOCKS_IRIX -extern int DEBUGLEVEL; static int oplock_pipe_write = -1; static int oplock_pipe_read = -1; /**************************************************************************** -test to see if IRIX kernel oplocks work + Test to see if IRIX kernel oplocks work. ****************************************************************************/ + static BOOL irix_oplocks_available(void) { int fd; @@ -82,106 +82,113 @@ Disabling kernel oplock support.\n", strerror(errno) )); return True; } - - /**************************************************************************** * Deal with the IRIX kernel <--> smbd * oplock break protocol. ****************************************************************************/ + static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len) { extern int smb_read_error; - oplock_stat_t os; - SMB_DEV_T dev; - SMB_INO_T inode; - char dummy; - - /* - * Read one byte of zero to clear the - * kernel break notify message. - */ - - if(read(oplock_pipe_read, &dummy, 1) != 1) { - DEBUG(0,("receive_local_message: read of kernel notification failed. \ + oplock_stat_t os; + char dummy; + files_struct *fsp; + + /* + * Read one byte of zero to clear the + * kernel break notify message. + */ + + if(read(oplock_pipe_read, &dummy, 1) != 1) { + DEBUG(0,("receive_local_message: read of kernel notification failed. \ Error was %s.\n", strerror(errno) )); - smb_read_error = READ_ERROR; - return False; - } - - /* - * Do a query to get the - * device and inode of the file that has the break - * request outstanding. - */ - - if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { - DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \ + smb_read_error = READ_ERROR; + return False; + } + + /* + * Do a query to get the + * device and inode of the file that has the break + * request outstanding. + */ + + if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { + DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \ Error was %s.\n", strerror(errno) )); - if(errno == EAGAIN) { - /* - * Duplicate kernel break message - ignore. - */ - memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN); - return True; - } - smb_read_error = READ_ERROR; - return False; - } - - dev = (SMB_DEV_T)os.os_dev; - inode = (SMB_INO_T)os.os_ino; - - DEBUG(5,("receive_local_message: kernel oplock break request received for \ -dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode )); - - /* - * Create a kernel oplock break message. - */ - - /* Setup the message header */ - SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN); - SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0); - - buffer += OPBRK_CMD_HEADER_LEN; + if(errno == EAGAIN) { + /* + * Duplicate kernel break message - ignore. + */ + memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN); + return True; + } + smb_read_error = READ_ERROR; + return False; + } + + /* + * We only have device and inode info here - we have to guess that this + * is the first fsp open with this dev,ino pair. + */ + + if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev, (SMB_INO_T)os.os_ino)) == NULL) { + DEBUG(0,("receive_local_message: unable to find open file with dev = %x, inode = %.0f\n", + (unsigned int)os.os_dev, (double)os.os_ino )); + return False; + } - SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD); + DEBUG(5,("receive_local_message: kernel oplock break request received for \ +dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id )); - memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev)); - memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode)); + /* + * Create a kernel oplock break message. + */ + + /* Setup the message header */ + SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN); + SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0); + + buffer += OPBRK_CMD_HEADER_LEN; - return True; + SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD); + + memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev)); + memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode)); + memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id)); + + return True; } - /**************************************************************************** Attempt to set an kernel oplock on a file. ****************************************************************************/ + static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type) { if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) { if(errno != EAGAIN) { DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \ -inode = %.0f. Error was %s\n", - fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, +inode = %.0f, file_id = %ul. Error was %s\n", + fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, strerror(errno) )); } else { DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ -inode = %.0f. Another process had the file open.\n", - fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode )); +inode = %.0f, file_id = %ul. Another process had the file open.\n", + fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id )); } return False; } - DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n", - fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode)); + DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n", + fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id)); return True; } - /**************************************************************************** Release a kernel oplock on a file. ****************************************************************************/ + static void irix_release_kernel_oplock(files_struct *fsp) { if (DEBUGLVL(10)) { @@ -190,9 +197,9 @@ static void irix_release_kernel_oplock(files_struct *fsp) * oplock state of this file. */ int state = fcntl(fsp->fd, F_OPLKACK, -1); - dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \ + dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, state ); + (double)fsp->inode, fsp->file_id, state ); } /* @@ -201,18 +208,19 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) { if( DEBUGLVL( 0 )) { dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " ); - dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n", + dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n", fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, strerror(errno) ); + (double)fsp->inode, fsp->file_id, strerror(errno) ); } } } - /**************************************************************************** -parse a kernel oplock message + Parse a kernel oplock message. ****************************************************************************/ -static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev) + +static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, + SMB_INO_T *inode, SMB_DEV_T *dev, unsigned long *file_id) { /* Ensure that the msg length is correct. */ if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) { @@ -221,36 +229,39 @@ static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *in return False; } - memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode)); - memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); + memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode)); + memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); + memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id)); - DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f\n", - (unsigned int)*dev, (double)*inode)); + DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %ul\n", + (unsigned int)*dev, (double)*inode, *file_id)); return True; } - /**************************************************************************** -set *maxfd to include oplock read pipe + Set *maxfd to include oplock read pipe. ****************************************************************************/ + static BOOL irix_oplock_msg_waiting(fd_set *fds) { - if (oplock_pipe_read == -1) return False; + if (oplock_pipe_read == -1) + return False; return FD_ISSET(oplock_pipe_read,fds); } - /**************************************************************************** -setup kernel oplocks + Setup kernel oplocks. ****************************************************************************/ + struct kernel_oplocks *irix_init_kernel_oplocks(void) { int pfd[2]; static struct kernel_oplocks koplocks; - if (!irix_oplocks_available()) return NULL; + if (!irix_oplocks_available()) + return NULL; if(pipe(pfd) != 0) { DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n", @@ -270,9 +281,6 @@ struct kernel_oplocks *irix_init_kernel_oplocks(void) return &koplocks; } - - - #else void oplock_irix_dummy(void) {} #endif /* HAVE_KERNEL_OPLOCKS_IRIX */ diff --git a/source/smbd/oplock_linux.c b/source/smbd/oplock_linux.c index 39ee3eb86b3..3f22956aa02 100644 --- a/source/smbd/oplock_linux.c +++ b/source/smbd/oplock_linux.c @@ -23,8 +23,6 @@ #if HAVE_KERNEL_OPLOCKS_LINUX -extern int DEBUGLEVEL; - static VOLATILE sig_atomic_t signals_received; static VOLATILE sig_atomic_t signals_processed; static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */ @@ -50,8 +48,9 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal #endif /**************************************************************************** -handle a LEASE signal, incrementing the signals_received and blocking the signal + Handle a LEASE signal, incrementing the signals_received and blocking the signal. ****************************************************************************/ + static void signal_handler(int sig, siginfo_t *info, void *unused) { BlockSignals(True, sig); @@ -61,8 +60,10 @@ static void signal_handler(int sig, siginfo_t *info, void *unused) } /**************************************************************************** -try to gain a linux capability -****************************************************************************/static void set_capability(unsigned capability) + Try to gain a linux capability. +****************************************************************************/ + +static void set_capability(unsigned capability) { #ifndef _LINUX_CAPABILITY_VERSION #define _LINUX_CAPABILITY_VERSION 0x19980330 @@ -94,11 +95,11 @@ try to gain a linux capability } } - /**************************************************************************** -call SETLEASE. If we get EACCES then we try setting up the right capability and -try again + Call SETLEASE. If we get EACCES then we try setting up the right capability and + try again ****************************************************************************/ + static int linux_setlease(int fd, int leasetype) { int ret; @@ -117,31 +118,27 @@ static int linux_setlease(int fd, int leasetype) return ret; } - /**************************************************************************** * Deal with the Linux kernel <--> smbd * oplock break protocol. ****************************************************************************/ + static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len) { - SMB_DEV_T dev; - SMB_INO_T inode; - SMB_STRUCT_STAT sbuf; BOOL ret = True; + struct files_struct *fsp; - if (signals_received == signals_processed) return False; + if (signals_received == signals_processed) + return False; - if (sys_fstat((int)fd_pending,&sbuf) == -1) { + if ((fsp = file_find_fd(fd_pending)) == NULL) { DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending)); ret = False; goto out; } - dev = sbuf.st_dev; - inode = sbuf.st_ino; - DEBUG(3,("receive_local_message: kernel oplock break request received for \ -dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode )); +dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode )); /* * Create a kernel oplock break message. @@ -155,8 +152,9 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode )); SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD); - memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev)); - memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode)); + memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev)); + memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode)); + memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id)); out: /* now we can receive more signals */ @@ -167,10 +165,10 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode )); return ret; } - /**************************************************************************** Attempt to set an kernel oplock on a file. ****************************************************************************/ + static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type) { if (linux_setlease(fsp->fd, F_WRLCK) == -1) { @@ -181,16 +179,16 @@ inode = %.0f. (%s)\n", return False; } - DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n", - fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode)); + DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n", + fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id)); return True; } - /**************************************************************************** Release a kernel oplock on a file. ****************************************************************************/ + static void linux_release_kernel_oplock(files_struct *fsp) { if (DEBUGLVL(10)) { @@ -199,9 +197,9 @@ static void linux_release_kernel_oplock(files_struct *fsp) * oplock state of this file. */ int state = fcntl(fsp->fd, F_GETLEASE, 0); - dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \ + dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, state ); + (double)fsp->inode, fsp->file_id, state ); } /* @@ -210,18 +208,19 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, if (linux_setlease(fsp->fd, F_UNLCK) == -1) { if (DEBUGLVL(0)) { dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " ); - dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n", + dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n", fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, strerror(errno) ); + (double)fsp->inode, fsp->file_id, strerror(errno) ); } } } - /**************************************************************************** -parse a kernel oplock message + Parse a kernel oplock message. ****************************************************************************/ -static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev) + +static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, + SMB_DEV_T *dev, unsigned long *file_id) { /* Ensure that the msg length is correct. */ if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) { @@ -230,41 +229,44 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i return False; } - memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode)); - memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); + memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode)); + memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); + memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id)); - DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f\n", - (unsigned int)*dev, (double)*inode)); + DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %lu\n", + (unsigned int)*dev, (double)*inode, *file_id)); return True; } - /**************************************************************************** -see if a oplock message is waiting + See if a oplock message is waiting. ****************************************************************************/ + static BOOL linux_oplock_msg_waiting(fd_set *fds) { return signals_processed != signals_received; } /**************************************************************************** -see if the kernel supports oplocks + See if the kernel supports oplocks. ****************************************************************************/ + static BOOL linux_oplocks_available(void) { int fd, ret; fd = open("/dev/null", O_RDONLY); - if (fd == -1) return False; /* uggh! */ + if (fd == -1) + return False; /* uggh! */ ret = fcntl(fd, F_GETLEASE, 0); close(fd); return ret == F_UNLCK; } - /**************************************************************************** -setup kernel oplocks + Setup kernel oplocks. ****************************************************************************/ + struct kernel_oplocks *linux_init_kernel_oplocks(void) { static struct kernel_oplocks koplocks; @@ -275,13 +277,13 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void) return NULL; } - act.sa_handler = NULL; - act.sa_sigaction = signal_handler; - act.sa_flags = SA_SIGINFO; - if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) { + act.sa_handler = NULL; + act.sa_sigaction = signal_handler; + act.sa_flags = SA_SIGINFO; + if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) { DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n")); return NULL; - } + } koplocks.receive_message = linux_oplock_receive_message; koplocks.set_oplock = linux_set_kernel_oplock; @@ -294,9 +296,6 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void) return &koplocks; } - - - #else void oplock_linux_dummy(void) {} #endif /* HAVE_KERNEL_OPLOCKS_LINUX */ diff --git a/source/smbd/password.c b/source/smbd/password.c index c6be5f68eda..4ccade52cec 100644 --- a/source/smbd/password.c +++ b/source/smbd/password.c @@ -21,7 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern int Protocol; extern struct in_addr ipzero; @@ -44,6 +43,7 @@ static BOOL challenge_sent=False; /******************************************************************* Get the next challenge value - no repeats. ********************************************************************/ + void generate_next_challenge(char *challenge) { unsigned char buf[8]; @@ -56,23 +56,26 @@ void generate_next_challenge(char *challenge) } /******************************************************************* -set the last challenge sent, usually from a password server + Set the last challenge sent, usually from a password server. ********************************************************************/ + BOOL set_challenge(unsigned char *challenge) { - memcpy(saved_challenge,challenge,8); - challenge_sent = True; - return(True); + memcpy(saved_challenge,challenge,8); + challenge_sent = True; + return(True); } /******************************************************************* -get the last challenge sent + Get the last challenge sent. ********************************************************************/ + static BOOL last_challenge(unsigned char *challenge) { - if (!challenge_sent) return(False); - memcpy(challenge,saved_challenge,8); - return(True); + if (!challenge_sent) + return(False); + memcpy(challenge,saved_challenge,8); + return(True); } /* this holds info on user ids that are already validated for this VC */ @@ -81,10 +84,11 @@ static int next_vuid = VUID_OFFSET; static int num_validated_vuids; /**************************************************************************** -check if a uid has been validated, and return an pointer to the user_struct -if it has. NULL if not. vuid is biased by an offset. This allows us to -tell random client vuid's (normally zero) from valid vuids. + Check if a uid has been validated, and return an pointer to the user_struct + if it has. NULL if not. vuid is biased by an offset. This allows us to + tell random client vuid's (normally zero) from valid vuids. ****************************************************************************/ + user_struct *get_valid_user_struct(uint16 vuid) { user_struct *usp; @@ -106,8 +110,9 @@ user_struct *get_valid_user_struct(uint16 vuid) } /**************************************************************************** -invalidate a uid + Invalidate a uid. ****************************************************************************/ + void invalidate_vuid(uint16 vuid) { user_struct *vuser = get_valid_user_struct(vuid); @@ -119,15 +124,16 @@ void invalidate_vuid(uint16 vuid) DLIST_REMOVE(validated_users, vuser); - safe_free(vuser->groups); + SAFE_FREE(vuser->groups); delete_nt_token(&vuser->nt_user_token); safe_free(vuser); num_validated_vuids--; } /**************************************************************************** -invalidate all vuid entries for this process + Invalidate all vuid entries for this process. ****************************************************************************/ + void invalidate_all_vuids(void) { user_struct *usp, *next=NULL; @@ -140,8 +146,9 @@ void invalidate_all_vuids(void) } /**************************************************************************** -return a validated username + Return a validated username. ****************************************************************************/ + char *validated_username(uint16 vuid) { user_struct *vuser = get_valid_user_struct(vuid); @@ -151,8 +158,9 @@ char *validated_username(uint16 vuid) } /**************************************************************************** -return a validated domain + Return a validated domain. ****************************************************************************/ + char *validated_domain(uint16 vuid) { user_struct *vuser = get_valid_user_struct(vuid); @@ -161,12 +169,11 @@ char *validated_domain(uint16 vuid) return(vuser->user.domain); } - /**************************************************************************** Create the SID list for this user. ****************************************************************************/ -NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest) +NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest, NT_USER_TOKEN *sup_tok) { extern DOM_SID global_sid_World; extern DOM_SID global_sid_Network; @@ -186,8 +193,11 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, /* We always have uid/gid plus World and Network and Authenticated Users or Guest SIDs. */ num_sids = 5 + ngroups; + if (sup_tok && sup_tok->num_sids) + num_sids += sup_tok->num_sids; + if ((token->user_sids = (DOM_SID *)malloc( num_sids*sizeof(DOM_SID))) == NULL) { - free(token); + SAFE_FREE(token); return NULL; } @@ -198,13 +208,15 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, * se_access_check depends on this. */ - uid_to_sid( &psids[psid_ndx++], uid); + uid_to_sid( &psids[PRIMARY_USER_SID_INDEX], uid); + psid_ndx++; /* * Primary group SID is second in token. Convention. */ - gid_to_sid( &psids[psid_ndx++], gid); + gid_to_sid( &psids[PRIMARY_GROUP_SID_INDEX], gid); + psid_ndx++; /* Now add the group SIDs. */ @@ -214,6 +226,12 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, } } + /* Now add the additional SIDs from the supplimentary token. */ + if (sup_tok) { + for (i = 0; i < sup_tok->num_sids; i++) + sid_copy( &psids[psid_ndx++], &sup_tok->user_sids[i] ); + } + /* * Finally add the "standard" SIDs. * The only difference between guest and "anonymous" (which we @@ -241,13 +259,13 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, } /**************************************************************************** -register a uid/name pair as being valid and that a valid password -has been given. vuid is biased by an offset. This allows us to -tell random client vuid's (normally zero) from valid vuids. + Register a uid/name pair as being valid and that a valid password + has been given. vuid is biased by an offset. This allows us to + tell random client vuid's (normally zero) from valid vuids. ****************************************************************************/ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, - char *domain,BOOL guest) + char *domain,BOOL guest, NT_USER_TOKEN **pptok) { user_struct *vuser = NULL; struct passwd *pwfile; /* for getting real name from passwd file */ @@ -292,12 +310,15 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, vuser->groups = NULL; /* Find all the groups this uid is in and store them. - Used by become_user() */ + Used by change_to_user() */ initialise_groups(unix_name, uid, gid); get_current_groups( &vuser->n_groups, &vuser->groups); + if (*pptok) + add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, pptok); + /* Create an NT_USER_TOKEN struct for this user. */ - vuser->nt_user_token = create_nt_token(uid,gid, vuser->n_groups, vuser->groups, guest); + vuser->nt_user_token = create_nt_token(uid,gid, vuser->n_groups, vuser->groups, guest, *pptok); next_vuid++; num_validated_vuids++; @@ -321,33 +342,32 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, return vuser->vuid; } - /**************************************************************************** -add a name to the session users list + Add a name to the session users list. ****************************************************************************/ + void add_session_user(char *user) { - fstring suser; - StrnCpy(suser,user,sizeof(suser)-1); + fstring suser; + StrnCpy(suser,user,sizeof(suser)-1); - if (!Get_Pwnam(suser,True)) return; + if (!Get_Pwnam(suser,True)) + return; - if (suser && *suser && !in_list(suser,session_users,False)) - { - if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring)) - DEBUG(1,("Too many session users??\n")); - else - { - pstrcat(session_users," "); - pstrcat(session_users,suser); + if (suser && *suser && !in_list(suser,session_users,False)) { + if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring)) + DEBUG(1,("Too many session users??\n")); + else { + pstrcat(session_users," "); + pstrcat(session_users,suser); + } } - } } - /**************************************************************************** -update the encrypted smbpasswd file from the plaintext username and password + Update the encrypted smbpasswd file from the plaintext username and password. *****************************************************************************/ + static BOOL update_smbpassword_file(char *user, char *password) { SAM_ACCOUNT *sampass = NULL; @@ -383,56 +403,55 @@ static BOOL update_smbpassword_file(char *user, char *password) return ret; } - - - - /**************************************************************************** -core of smb password checking routine. + Core of smb password checking routine. ****************************************************************************/ + BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8) { - /* Finish the encryption of part_passwd. */ - unsigned char p21[21]; - unsigned char p24[24]; - - if (part_passwd == NULL) - DEBUG(10,("No password set - allowing access\n")); - /* No password set - always true ! */ - if (part_passwd == NULL) - return 1; - - memset(p21,'\0',21); - memcpy(p21,part_passwd,16); - E_P24(p21, c8, p24); + /* Finish the encryption of part_passwd. */ + unsigned char p21[21]; + unsigned char p24[24]; + + if (part_passwd == NULL) + DEBUG(10,("No password set - allowing access\n")); + + /* No password set - always true ! */ + if (part_passwd == NULL) + return True; + + memset(p21,'\0',21); + memcpy(p21,part_passwd,16); + E_P24(p21, c8, p24); #if DEBUG_PASSWORD - { - int i; - DEBUG(100,("Part password (P16) was |")); - for(i = 0; i < 16; i++) - DEBUG(100,("%X ", (unsigned char)part_passwd[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Password from client was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)password[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Given challenge was |")); - for(i = 0; i < 8; i++) - DEBUG(100,("%X ", (unsigned char)c8[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Value from encryption was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)p24[i])); - DEBUG(100,("|\n")); - } + { + int i; + DEBUG(100,("Part password (P16) was |")); + for(i = 0; i < 16; i++) + DEBUG(100,("%X ", (unsigned char)part_passwd[i])); + DEBUG(100,("|\n")); + DEBUG(100,("Password from client was |")); + for(i = 0; i < 24; i++) + DEBUG(100,("%X ", (unsigned char)password[i])); + DEBUG(100,("|\n")); + DEBUG(100,("Given challenge was |")); + for(i = 0; i < 8; i++) + DEBUG(100,("%X ", (unsigned char)c8[i])); + DEBUG(100,("|\n")); + DEBUG(100,("Value from encryption was |")); + for(i = 0; i < 24; i++) + DEBUG(100,("%X ", (unsigned char)p24[i])); + DEBUG(100,("|\n")); + } #endif - return (memcmp(p24, password, 24) == 0); + return (memcmp(p24, password, 24) == 0); } /**************************************************************************** Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ + BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8], uchar lm_pass[24], uchar nt_pass[24]) { @@ -482,8 +501,7 @@ BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8], lm_pw = pdb_get_lanman_passwd(sampass); - if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) - { + if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) { DEBUG(4,("smb_password_ok: no password required for user %s\n",user_name)); return True; } @@ -500,11 +518,9 @@ BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8], return False; } - /**************************************************************************** -check if a username/password is OK assuming the password is a 24 byte -SMB hash -return True if the password is correct, False otherwise + Check if a username/password is OK assuming the password is a 24 byte + SMB hash. Return True if the password is correct, False otherwise. ****************************************************************************/ BOOL pass_check_smb(char *user, char *domain, uchar *chal, @@ -513,27 +529,21 @@ BOOL pass_check_smb(char *user, char *domain, uchar *chal, SAM_ACCOUNT *sampass = NULL; if (!lm_pwd || !nt_pwd) - { return(False); - } #if 0 /* JERRY */ /* FIXME! this code looks to be unnecessary now that the passdb validates that the username exists and has a valid uid */ - if (pwd != NULL && user == NULL) - { + if (pwd != NULL && user == NULL) { pass = (struct passwd *) pwd; user = pass->pw_name; - } - else - { + } else { /* I don't get this call here. I think it should be moved. Need to check on it. --jerry */ pass = smb_getpwnam(user,True); } - if (pass == NULL) - { + if (pass == NULL) { DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",user)); return(False); } @@ -541,8 +551,7 @@ BOOL pass_check_smb(char *user, char *domain, uchar *chal, /* get the account information */ pdb_init_sam(&sampass); - if (!pdb_getsampwnam(sampass, user)) - { + if (!pdb_getsampwnam(sampass, user)) { DEBUG(1,("Couldn't find user '%s' in passdb.\n", user)); return(False); } @@ -550,39 +559,40 @@ BOOL pass_check_smb(char *user, char *domain, uchar *chal, /* Quit if the account was disabled. */ if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) { DEBUG(1,("Account for user '%s' was disabled.\n", user)); + pdb_free_sam(sampass); return(False); } - if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) - { - if (lp_null_passwords()) - { + if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) { + if (lp_null_passwords()) { DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", user)); + pdb_free_sam(sampass); return(True); - } - else - { + } else { DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", user)); + pdb_free_sam(sampass); return(False); } } - if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd)) - { + if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd)) { + pdb_free_sam(sampass); return(True); } - + DEBUG(2,("pass_check_smb failed - invalid password for user [%s]\n", user)); + pdb_free_sam(sampass); return False; } /**************************************************************************** -check if a username/password pair is OK either via the system password -database or the encrypted SMB password database -return True if the password is correct, False otherwise + Check if a username/password pair is OK either via the system password + database or the encrypted SMB password database + return True if the password is correct, False otherwise. ****************************************************************************/ + BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd) { @@ -612,7 +622,7 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd) */ if (ret) - return (smb_pam_accountcheck(user) == NT_STATUS_OK); + return (NT_STATUS_V(smb_pam_accountcheck(user)) == NT_STATUS_V(NT_STATUS_OK)); return ret; } @@ -623,8 +633,9 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd) } /**************************************************************************** -check if a username is valid + Check if a username is valid ****************************************************************************/ + BOOL user_ok(char *user,int snum) { pstring valid, invalid; @@ -638,9 +649,8 @@ BOOL user_ok(char *user,int snum) ret = !user_in_list(user,invalid); - if (ret && valid && *valid) { + if (ret && valid && *valid) ret = user_in_list(user,valid); - } if (ret && lp_onlyuser(snum)) { char *user_list = lp_username(snum); @@ -651,13 +661,11 @@ BOOL user_ok(char *user,int snum) return(ret); } - - - /**************************************************************************** -validate a group username entry. Return the username or NULL + Validate a group username entry. Return the username or NULL. ****************************************************************************/ -static char *validate_group(char *group,char *password,int pwlen,int snum) + +static char *validate_group(const char *group,char *password,int pwlen,int snum) { #ifdef HAVE_NETGROUP { @@ -676,66 +684,24 @@ static char *validate_group(char *group,char *password,int pwlen,int snum) } #endif -#ifdef HAVE_GETGRENT { - struct group *gptr; - setgrent(); - while ((gptr = (struct group *)getgrent())) { - if (strequal(gptr->gr_name,group)) - break; - } - - /* - * As user_ok can recurse doing a getgrent(), we must - * copy the member list into a pstring on the stack before - * use. Bug pointed out by leon@eatworms.swmed.edu. - */ - - if (gptr) { - pstring member_list; - char *member; - size_t copied_len = 0; - int i; - - *member_list = '\0'; - member = member_list; - - for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) { - size_t member_len = strlen(gptr->gr_mem[i]) + 1; - if( copied_len + member_len < sizeof(pstring)) { - - DEBUG(10,("validate_group: = gr_mem = %s\n", gptr->gr_mem[i])); - - safe_strcpy(member, gptr->gr_mem[i], sizeof(pstring) - copied_len - 1); - copied_len += member_len; - member += copied_len; - } else { - *member = '\0'; - } + struct sys_userlist *user_list = get_users_in_group(group); + struct sys_userlist *member; + + for (member = user_list; member; member = member->next) { + static fstring name; + fstrcpy(name,member->unix_name); + if (user_ok(name,snum) && + password_ok(name,password,pwlen,NULL)) { + free_userlist(user_list); + return(&name[0]); } - endgrent(); - - member = member_list; - while (*member) { - static fstring name; - fstrcpy(name,member); - if (user_ok(name,snum) && - password_ok(name,password,pwlen,NULL)) { - endgrent(); - return(&name[0]); - } - - DEBUG(10,("validate_group = member = %s\n", member)); - - member += strlen(member) + 1; - } - } else { - endgrent(); - return NULL; + DEBUG(10,("validate_group = member = %s\n", member->unix_name)); } + free_userlist(user_list); } -#endif + return(NULL); } @@ -835,7 +801,7 @@ and given password ok\n", user)); } } - free(user_list); + SAFE_FREE(user_list); } /* check for a previously validated username/password pair */ @@ -864,7 +830,7 @@ and given password ok\n", user)); pstring_sub(user_list,"%S",lp_servicename(snum)); for (auser=strtok(user_list,LIST_SEP); auser && !ok; - auser = strtok(NULL,LIST_SEP)) { + auser = strtok(NULL,LIST_SEP)) { if (*auser == '@') { auser = validate_group(auser+1,password,pwlen,snum); if (auser) { @@ -1016,41 +982,39 @@ static BOOL check_user_equiv(char *user, char *remote, char *equiv_file) return False; } - /**************************************************************************** -check for a possible hosts equiv or rhosts entry for the user + Check for a possible hosts equiv or rhosts entry for the user. ****************************************************************************/ + BOOL check_hosts_equiv(char *user) { - char *fname = NULL; - pstring rhostsfile; - struct passwd *pass = Get_Pwnam(user,True); + char *fname = NULL; + pstring rhostsfile; + struct passwd *pass = Get_Pwnam(user,True); - if (!pass) - return(False); + if (!pass) + return(False); - fname = lp_hosts_equiv(); + fname = lp_hosts_equiv(); - /* note: don't allow hosts.equiv on root */ - if (fname && *fname && (pass->pw_uid != 0)) { - if (check_user_equiv(user,client_name(),fname)) - return(True); - } + /* note: don't allow hosts.equiv on root */ + if (fname && *fname && (pass->pw_uid != 0)) { + if (check_user_equiv(user,client_name(),fname)) + return(True); + } - if (lp_use_rhosts()) - { - char *home = get_user_home_dir(user); - if (home) { - slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); - if (check_user_equiv(user,client_name(),rhostsfile)) - return(True); - } - } + if (lp_use_rhosts()) { + char *home = get_user_service_home_dir(user); + if (home) { + slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); + if (check_user_equiv(user,client_name(),rhostsfile)) + return(True); + } + } - return(False); + return(False); } - /**************************************************************************** Return the client state structure. ****************************************************************************/ @@ -1102,7 +1066,7 @@ struct cli_state *server_cryptkey(void) } } - free(pserver); + SAFE_FREE(pserver); if (!connected_ok) { DEBUG(0,("password server not available\n")); @@ -1266,7 +1230,7 @@ static BOOL connect_to_domain_password_server(struct cli_state *pcli, return False; } - if (!name_status_find(0x20, to_ip, remote_machine)) { + if (!name_status_find("*", 0, 0x20, to_ip, remote_machine)) { DEBUG(1, ("connect_to_domain_password_server: Can't " "resolve name for IP %s\n", server)); return False; @@ -1367,7 +1331,7 @@ machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli))); return False; } - if (cli_nt_setup_creds(pcli, trust_passwd) == False) { + if (!NT_STATUS_IS_OK(cli_nt_setup_creds(pcli, trust_passwd))) { DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \ %s. Error was : %s.\n", remote_machine, cli_errstr(pcli))); cli_nt_session_close(pcli); @@ -1394,18 +1358,17 @@ static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip, un if (ip_equal(ipzero, *ip)) return False; - if (!lookup_pdc_name(global_myname, lp_workgroup(), ip, dc_name)) + if (!lookup_dc_name(global_myname, lp_workgroup(), ip, dc_name)) return False; return connect_to_domain_password_server(pcli, dc_name, trust_passwd); } - - /*********************************************************************** We have been asked to dynamcially determine the IP addresses of the PDC and BDC's for this DOMAIN, and query them in turn. ************************************************************************/ + static BOOL find_connect_pdc(struct cli_state *pcli, unsigned char *trust_passwd, time_t last_change_time) { struct in_addr *ip_list = NULL; @@ -1468,15 +1431,11 @@ static BOOL find_connect_pdc(struct cli_state *pcli, unsigned char *trust_passwd } } - if(ip_list != NULL) - free((char *)ip_list); - + SAFE_FREE(ip_list); return connected_ok; } - - /*********************************************************************** Do the same as security=server, but using NT Domain calls and a session key from the machine password. @@ -1485,7 +1444,7 @@ static BOOL find_connect_pdc(struct cli_state *pcli, unsigned char *trust_passwd BOOL domain_client_validate( char *user, char *domain, char *smb_apasswd, int smb_apasslen, char *smb_ntpasswd, int smb_ntpasslen, - BOOL *user_exists) + BOOL *user_exists, NT_USER_TOKEN **pptoken) { unsigned char local_challenge[8]; unsigned char local_lm_response[24]; @@ -1499,6 +1458,10 @@ BOOL domain_client_validate( char *user, char *domain, uint32 smb_uid_low; BOOL connected_ok = False; time_t last_change_time; + NTSTATUS status; + + if (pptoken) + *pptoken = NULL; if(user_exists != NULL) *user_exists = True; /* Only set false on a very specific error. */ @@ -1598,20 +1561,20 @@ BOOL domain_client_validate( char *user, char *domain, ZERO_STRUCT(info3); - if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge, + status = cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge, ((smb_apasslen != 0) ? smb_apasswd : NULL), ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL), - &ctr, &info3) == False) { - uint32 nt_rpc_err; + &ctr, &info3); + + if (!NT_STATUS_IS_OK(status)) { - cli_error(&cli, NULL, NULL, &nt_rpc_err); DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \ -%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli))); +%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, get_nt_error_msg(status) )); cli_nt_session_close(&cli); cli_ulogoff(&cli); cli_shutdown(&cli); - if((nt_rpc_err == NT_STATUS_NO_SUCH_USER) && (user_exists != NULL)) + if((NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NO_SUCH_USER)) && (user_exists != NULL)) *user_exists = False; return False; @@ -1621,6 +1584,43 @@ BOOL domain_client_validate( char *user, char *domain, * Here, if we really want it, we have lots of info about the user in info3. */ + /* Return group membership as returned by NT. This contains group + membership in nested groups which doesn't seem to be accessible by any + other means. We merge this into the NT_USER_TOKEN associated with the vuid + later on. */ + + if (pptoken && (info3.num_groups2 != 0)) { + NT_USER_TOKEN *ptok; + int i; + DOM_SID domain_sid; + + *pptoken = NULL; + + if ((ptok = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) { + DEBUG(0, ("domain_client_validate: Out of memory allocating NT_USER_TOKEN\n")); + return False; + } + + ptok->num_sids = (size_t)info3.num_groups2; + if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) { + DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n")); + SAFE_FREE(ptok); + return False; + } + + if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { + DEBUG(0, ("domain_client_validate: unable to fetch domain sid.\n")); + delete_nt_token(&ptok); + return False; + } + + for (i = 0; i < ptok->num_sids; i++) { + sid_copy(&ptok->user_sids[i], &domain_sid); + sid_append_rid(&ptok->user_sids[i], info3.gids[i].g_rid); + } + *pptoken = ptok; + } + #if 0 /* * We don't actually need to do this - plus it fails currently with diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c index 366707cd589..2837187f4bf 100644 --- a/source/smbd/pipes.c +++ b/source/smbd/pipes.c @@ -31,8 +31,6 @@ #define PIPE "\\PIPE\\" #define PIPELEN strlen(PIPE) -extern int DEBUGLEVEL; - extern struct pipe_id_info pipe_names[]; /**************************************************************************** @@ -58,7 +56,7 @@ int reply_open_pipe_and_X(connection_struct *conn, /* at a mailslot or something we really, really don't understand, */ /* not just something we really don't understand. */ if ( strncmp(fname,PIPE,PIPELEN) != 0 ) - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); DEBUG(4,("Opening pipe %s.\n", fname)); @@ -68,7 +66,7 @@ int reply_open_pipe_and_X(connection_struct *conn, break; if (pipe_names[i].client_pipe == NULL) - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); /* Strip \PIPE\ off the name. */ pstrcpy(fname,smb_buf(inbuf) + PIPELEN); @@ -78,7 +76,7 @@ int reply_open_pipe_and_X(connection_struct *conn, * Hack for NT printers... JRA. */ if(should_fail_next_srvsvc_open(fname)) - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); #endif /* Known pipes arrive with DIR attribs. Remove it so a regular file */ @@ -87,7 +85,7 @@ int reply_open_pipe_and_X(connection_struct *conn, smb_ofun |= FILE_CREATE_IF_NOT_EXIST; p = open_rpc_pipe_p(fname, conn, vuid); - if (!p) return(ERROR(ERRSRV,ERRnofids)); + if (!p) return(ERROR_DOS(ERRSRV,ERRnofids)); /* Prepare the reply */ set_message(outbuf,15,0,True); @@ -123,7 +121,7 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) char *data; if (!p) - return(ERROR(ERRDOS,ERRbadfid)); + return(ERROR_DOS(ERRDOS,ERRbadfid)); data = smb_buf(inbuf) + 3; @@ -163,7 +161,7 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) char *data; if (!p) - return(ERROR(ERRDOS,ERRbadfid)); + return(ERROR_DOS(ERRDOS,ERRbadfid)); data = smb_base(inbuf) + smb_doff; @@ -223,7 +221,7 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) #endif if (!p) - return(ERROR(ERRDOS,ERRbadfid)); + return(ERROR_DOS(ERRDOS,ERRbadfid)); set_message(outbuf,12,0,True); data = smb_buf(outbuf); @@ -252,12 +250,12 @@ int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf) int outsize = set_message(outbuf,0,0,True); if (!p) - return(ERROR(ERRDOS,ERRbadfid)); + return(ERROR_DOS(ERRDOS,ERRbadfid)); DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum)); if (!close_rpc_pipe_hnd(p, conn)) - return(ERROR(ERRDOS,ERRbadfid)); + return(ERROR_DOS(ERRDOS,ERRbadfid)); return(outsize); } diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 5c22b89a8d8..99c5760314b 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -38,7 +38,7 @@ typedef struct canon_ace { struct canon_ace *next, *prev; SMB_ACL_TAG_T type; mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */ - DOM_SID sid; + DOM_SID trustee; enum ace_owner owner_type; enum ace_attribute attr; posix_id unix_ug; @@ -74,7 +74,7 @@ static void free_canon_ace_list( canon_ace *list_head ) while (list_head) { canon_ace *old_head = list_head; DLIST_REMOVE(list_head, list_head); - free(old_head); + SAFE_FREE(old_head); } } @@ -103,13 +103,13 @@ static void print_canon_ace(canon_ace *pace, int num) fstring str; dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" ); - dbgtext( "SID = %s ", sid_to_string( str, &pace->sid)); + dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee)); if (pace->owner_type == UID_ACE) { - struct passwd *pass = sys_getpwuid(pace->unix_ug.uid); - dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, pass ? pass->pw_name : "UNKNOWN"); + char *u_name = uidtoname(pace->unix_ug.uid); + dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name); } else if (pace->owner_type == GID_ACE) { - struct group *grp = getgrgid(pace->unix_ug.gid); - dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, grp ? grp->gr_name : "UNKNOWN"); + char *g_name = gidtoname(pace->unix_ug.gid); + dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name); } else dbgtext( "other "); switch (pace->type) { @@ -243,7 +243,7 @@ static void merge_aces( canon_ace **pp_list_head ) curr_ace_next = curr_ace->next; /* Save the link in case of delete. */ - if (sid_equal(&curr_ace->sid, &curr_ace_outer->sid) && + if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && (curr_ace->attr == curr_ace_outer->attr)) { if( DEBUGLVL( 10 )) { @@ -256,7 +256,7 @@ static void merge_aces( canon_ace **pp_list_head ) curr_ace_outer->perms |= curr_ace->perms; DLIST_REMOVE(list_head, curr_ace); - free(curr_ace); + SAFE_FREE(curr_ace); curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ } } @@ -283,7 +283,7 @@ static void merge_aces( canon_ace **pp_list_head ) * we've put on the ACL, we know the deny must be the first one. */ - if (sid_equal(&curr_ace->sid, &curr_ace_outer->sid) && + if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) { if( DEBUGLVL( 10 )) { @@ -301,7 +301,7 @@ static void merge_aces( canon_ace **pp_list_head ) */ DLIST_REMOVE(list_head, curr_ace); - free(curr_ace); + SAFE_FREE(curr_ace); curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ } else { @@ -317,7 +317,8 @@ static void merge_aces( canon_ace **pp_list_head ) */ DLIST_REMOVE(list_head, curr_ace_outer); - free(curr_ace_outer); + SAFE_FREE(curr_ace_outer); + break; } } @@ -572,7 +573,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->type = SMB_ACL_USER_OBJ; pace->owner_type = UID_ACE; pace->unix_ug.uid = pst->st_uid; - pace->sid = *pfile_owner_sid; + pace->trustee = *pfile_owner_sid; pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); pace->attr = ALLOW_ACE; @@ -589,7 +590,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->type = SMB_ACL_GROUP_OBJ; pace->owner_type = GID_ACE; pace->unix_ug.uid = pst->st_gid; - pace->sid = *pfile_grp_sid; + pace->trustee = *pfile_grp_sid; pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); pace->attr = ALLOW_ACE; @@ -606,7 +607,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->type = SMB_ACL_OTHER; pace->owner_type = WORLD_ACE; pace->unix_ug.world = -1; - pace->sid = global_sid_World; + pace->trustee = global_sid_World; pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); pace->attr = ALLOW_ACE; @@ -688,7 +689,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp, if (psa1->info.mask != psa2->info.mask) continue; - if (!sid_equal(&psa1->sid, &psa2->sid)) + if (!sid_equal(&psa1->trustee, &psa2->trustee)) continue; /* @@ -718,10 +719,10 @@ static BOOL create_canon_ace_lists(files_struct *fsp, * Ignore non-mappable SIDs (NT Authority, BUILTIN etc). */ - if (non_mappable_sid(&psa->sid)) { + if (non_mappable_sid(&psa->trustee)) { fstring str; DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n", - sid_to_string(str, &psa->sid) )); + sid_to_string(str, &psa->trustee) )); continue; } @@ -738,28 +739,28 @@ static BOOL create_canon_ace_lists(files_struct *fsp, ZERO_STRUCTP(current_ace); - sid_copy(¤t_ace->sid, &psa->sid); + sid_copy(¤t_ace->trustee, &psa->trustee); /* * Try and work out if the SID is a user or group * as we need to flag these differently for POSIX. */ - if( sid_equal(¤t_ace->sid, &global_sid_World)) { + if( sid_equal(¤t_ace->trustee, &global_sid_World)) { current_ace->owner_type = WORLD_ACE; current_ace->unix_ug.world = -1; - } else if (sid_to_uid( ¤t_ace->sid, ¤t_ace->unix_ug.uid, &sid_type)) { + } else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid, &sid_type)) { current_ace->owner_type = UID_ACE; - } else if (sid_to_gid( ¤t_ace->sid, ¤t_ace->unix_ug.gid, &sid_type)) { + } else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid, &sid_type)) { current_ace->owner_type = GID_ACE; } else { fstring str; free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); - free(current_ace); DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n", - sid_to_string(str, ¤t_ace->sid) )); + sid_to_string(str, ¤t_ace->trustee) )); + SAFE_FREE(current_ace); return False; } @@ -775,15 +776,15 @@ static BOOL create_canon_ace_lists(files_struct *fsp, * Now note what kind of a POSIX ACL this should map to. */ - if(sid_equal(¤t_ace->sid, pfile_owner_sid)) { + if(sid_equal(¤t_ace->trustee, pfile_owner_sid)) { current_ace->type = SMB_ACL_USER_OBJ; - } else if( sid_equal(¤t_ace->sid, pfile_grp_sid)) { + } else if( sid_equal(¤t_ace->trustee, pfile_grp_sid)) { current_ace->type = SMB_ACL_GROUP_OBJ; - } else if( sid_equal(¤t_ace->sid, &global_sid_World)) { + } else if( sid_equal(¤t_ace->trustee, &global_sid_World)) { current_ace->type = SMB_ACL_OTHER; @@ -827,7 +828,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp, Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); - free(current_ace); + SAFE_FREE(current_ace); return False; } @@ -878,7 +879,7 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); - free(current_ace); + SAFE_FREE(current_ace); return False; } @@ -894,8 +895,7 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); * Free if ACE was not added. */ - if (current_ace) - free(current_ace); + SAFE_FREE(current_ace); } if (fsp->is_directory && all_aces_are_inherit_only) { @@ -926,26 +926,23 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) { extern DOM_SID global_sid_World; - struct passwd *pass = NULL; - struct group *gptr = NULL; + fstring u_name; + fstring g_name; /* "Everyone" always matches every uid. */ - if (sid_equal(&group_ace->sid, &global_sid_World)) + if (sid_equal(&group_ace->trustee, &global_sid_World)) return True; - if (!(pass = sys_getpwuid(uid_ace->unix_ug.uid))) - return False; - - if (!(gptr = getgrgid(group_ace->unix_ug.gid))) - return False; + fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); + fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); /* * Due to the winbind interfaces we need to do this via names, * not uids/gids. */ - return user_in_group_list(pass->pw_name, gptr->gr_name ); + return user_in_group_list(u_name, g_name ); } /**************************************************************************** @@ -1068,7 +1065,7 @@ static void process_deny_list( canon_ace **pp_ace_list ) continue; } - if (!sid_equal(&curr_ace->sid, &global_sid_World)) + if (!sid_equal(&curr_ace->trustee, &global_sid_World)) continue; /* JRATEST - assert. */ @@ -1519,7 +1516,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ ace->type = tagtype; ace->perms = convert_permset_to_mode_t(permset); ace->attr = ALLOW_ACE; - ace->sid = sid; + ace->trustee = sid; ace->unix_ug = unix_ug; ace->owner_type = owner_type; @@ -1720,6 +1717,12 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau if(default_ace || fsp->is_directory || fsp->fd == -1) { if (sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), the_acl_type, the_acl) == -1) { + /* + * Some systems allow all the above calls and only fail with no ACL support + * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. + */ + if (errno == ENOSYS) + *pacl_set_support = False; DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n", the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", fsp->fsp_name, strerror(errno) )); @@ -1727,6 +1730,12 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau } } else { if (sys_acl_set_fd(fsp->fd, the_acl) == -1) { + /* + * Some systems allow all the above calls and only fail with no ACL support + * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. + */ + if (errno == ENOSYS) + *pacl_set_support = False; DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n", fsp->fsp_name, strerror(errno) )); goto done; @@ -1938,14 +1947,14 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) for (i = 0; i < num_acls; i++, ace = ace->next) { SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); - init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0); + init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0); } ace = dir_ace; for (i = 0; i < num_dir_acls; i++, ace = ace->next) { SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); - init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, + init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); } @@ -1979,8 +1988,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) sys_acl_free_acl(dir_acl); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); - if (nt_ace_list) - free(nt_ace_list); + SAFE_FREE(nt_ace_list); return sd_size; } @@ -2244,7 +2252,7 @@ static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode) Note that name is in UNIX character set. ****************************************************************************/ -int chmod_acl(char *name, mode_t mode) +int chmod_acl(const char *name, mode_t mode) { SMB_ACL_T posix_acl = NULL; int ret = -1; diff --git a/source/smbd/process.c b/source/smbd/process.c index 5c329a7c8ac..1299fd20e3a 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -21,7 +21,8 @@ #include "includes.h" -extern int DEBUGLEVEL; +/* To be removed.... JRA */ +#define SMB_ALIGNMENT 1 struct timeval smb_last_time; @@ -44,9 +45,6 @@ int max_recv = BUFFER_SIZE; extern int last_message; extern int global_oplock_break; extern userdom_struct current_user_info; -extern char *last_inbuf; -extern char *InBuffer; -extern char *OutBuffer; extern int smb_read_error; extern VOLATILE sig_atomic_t reload_after_sighup; extern BOOL global_machine_password_needs_changing; @@ -87,7 +85,7 @@ static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len) if(msg->msg_buf == NULL) { DEBUG(0,("push_message: malloc fail (2)\n")); - free((char *)msg); + SAFE_FREE(msg); return False; } @@ -125,7 +123,7 @@ static void async_processing(fd_set *fds, char *buffer, int buffer_len) /* check for sighup processing */ if (reload_after_sighup) { - unbecome_user(); + change_to_root_user(); DEBUG(1,("Reloading services after SIGHUP\n")); reload_services(False); reload_after_sighup = False; @@ -180,8 +178,8 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); /* Free the message we just copied. */ - free((char *)msg->msg_buf); - free((char *)msg); + SAFE_FREE(msg->msg_buf); + SAFE_FREE(msg); DEBUG(5,("receive_message_or_smb: returning queued smb message.\n")); return True; @@ -199,7 +197,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) to.tv_sec = timeout / 1000; to.tv_usec = (timeout % 1000) * 1000; - selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL); + selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,timeout>0?&to:NULL); /* if we get EINTR then maybe we have received an oplock signal - treat this as select returning 1. This is ugly, but @@ -366,11 +364,11 @@ struct smb_message_struct /* 0x18 */ { NULL, NULL, 0 }, /* 0x19 */ { NULL, NULL, 0 }, /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER}, -/* 0x1b */ { "SMBreadBmpx",NULL,0}, +/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER}, /* 0x1c */ { "SMBreadBs",NULL,0}, /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER}, -/* 0x1e */ { "SMBwriteBmpx",NULL,0}, -/* 0x1f */ { "SMBwriteBs",NULL,0}, +/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER}, +/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER}, /* 0x20 */ { "SMBwritec",NULL,0}, /* 0x21 */ { NULL, NULL, 0 }, /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE }, @@ -615,7 +613,9 @@ static void smb_dump(char *name, int type, char *data, ssize_t len) if (fd != -1 || errno != EEXIST) break; } if (fd != -1) { - write(fd, data, len); + ssize_t ret = write(fd, data, len); + if (ret != len) + DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret )); close(fd); DEBUG(0,("created %s len %d\n", fname, len)); } @@ -708,20 +708,20 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize /* does this protocol need to be run as root? */ if (!(flags & AS_USER)) - unbecome_user(); + change_to_root_user(); /* does this protocol need a valid tree connection? */ if ((flags & AS_USER) && !conn) { - return ERROR(ERRSRV, ERRinvnid); + return ERROR_DOS(ERRSRV, ERRinvnid); } /* does this protocol need to be run as the connected user? */ - if ((flags & AS_USER) && !become_user(conn,session_tag)) { + if ((flags & AS_USER) && !change_to_user(conn,session_tag)) { if (flags & AS_GUEST) flags &= ~AS_USER; else - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); } /* this code is to work around a bug is MS client 3 without @@ -732,23 +732,23 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize /* does it need write permission? */ if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); /* ipc services are limited */ if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) { - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); } /* load service specific parameters */ - if (conn && !become_service(conn,(flags & AS_USER)?True:False)) { - return(ERROR(ERRSRV,ERRaccess)); + if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) { + return(ERROR_DOS(ERRSRV,ERRaccess)); } /* does this protocol need to be run as guest? */ if ((flags & AS_GUEST) && - (!become_guest() || + (!change_to_guest() || !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) { - return(ERROR(ERRSRV,ERRaccess)); + return(ERROR_DOS(ERRSRV,ERRaccess)); } last_inbuf = inbuf; @@ -797,7 +797,7 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) ****************************************************************************/ static BOOL smbd_process_limit(void) { - int total_smbds; + int32 total_smbds; if (lp_max_smbd_processes()) { @@ -813,7 +813,7 @@ set. Ignoring max smbd restriction.\n")); return False; } - if (tdb_change_int_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1) + if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1) return True; return total_smbds > lp_max_smbd_processes(); @@ -920,11 +920,11 @@ void construct_reply_common(char *inbuf,char *outbuf) memset(outbuf,'\0',smb_size); set_message(outbuf,0,0,True); - CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com); + SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); memcpy(outbuf+4,inbuf+4,4); - CVAL(outbuf,smb_rcls) = SMB_SUCCESS; - CVAL(outbuf,smb_reh) = 0; + SCVAL(outbuf,smb_rcls,SMB_SUCCESS); + SCVAL(outbuf,smb_reh,0); SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); /* bit 7 set means a reply */ SSVAL(outbuf,smb_flg2,FLAGS2_LONG_PATH_COMPONENTS); @@ -955,7 +955,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) /* maybe its not chained */ if (smb_com2 == 0xFF) { - CVAL(outbuf,smb_vwv0) = 0xFF; + SCVAL(outbuf,smb_vwv0,0xFF); return outsize; } @@ -975,7 +975,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) /* we need to tell the client where the next part of the reply will be */ SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf)); - CVAL(outbuf,smb_vwv0) = smb_com2; + SCVAL(outbuf,smb_vwv0,smb_com2); /* remember how much the caller added to the chain, only counting stuff after the parameter words */ @@ -997,7 +997,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) memmove(inbuf2,inbuf,smb_wct); /* create the in buffer */ - CVAL(inbuf2,smb_com) = smb_com2; + SCVAL(inbuf2,smb_com,smb_com2); /* create the out buffer */ construct_reply_common(inbuf2, outbuf2); @@ -1012,7 +1012,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) /* copy the new reply and request headers over the old ones, but preserve the smb_com field */ memmove(orig_outbuf,outbuf2,smb_wct); - CVAL(orig_outbuf,smb_com) = smb_com1; + SCVAL(orig_outbuf,smb_com,smb_com1); /* restore the saved data, being careful not to overwrite any data from the reply header */ @@ -1102,7 +1102,7 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t last_idle_closed_check = t; /* become root again if waiting */ - unbecome_user(); + change_to_root_user(); /* check if we need to reload services */ check_reload(t); @@ -1141,7 +1141,7 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t return False; } - if(global_machine_password_needs_changing) + if(global_machine_password_needs_changing && lp_security() == SEC_DOMAIN) { unsigned char trust_passwd_hash[16]; time_t lct; diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c index 46693a6fe1e..5e744bc97dd 100644 --- a/source/smbd/quotas.c +++ b/source/smbd/quotas.c @@ -28,8 +28,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - #if defined(VXFS_QUOTA) /* @@ -57,6 +55,9 @@ BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_B */ #include <linux/quota.h> +#ifdef HAVE_LINUX_XQM_H +#include <linux/xqm.h> +#endif #include <mntent.h> #include <linux/unistd.h> @@ -75,10 +76,35 @@ typedef struct _LINUX_SMB_DISK_QUOTA { } LINUX_SMB_DISK_QUOTA; /**************************************************************************** + Abstract out the XFS Quota Manager quota get call. +****************************************************************************/ + +static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp) +{ + int ret = -1; +#ifdef HAVE_LINUX_XQM_H + struct fs_disk_quota D; + ZERO_STRUCT(D); + + if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D))) + return ret; + + dp->bsize = (SMB_BIG_UINT)512; + dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit; + dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit; + dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit; + dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit; + dp->curinodes = (SMB_BIG_UINT)D.d_icount; + dp->curblocks = (SMB_BIG_UINT)D.d_bcount; +#endif + return ret; +} + +/**************************************************************************** Abstract out the old and new Linux quota get calls. ****************************************************************************/ -static int get_smb_linux_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp) +static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp) { int ret; #ifdef LINUX_QUOTAS_1 @@ -116,7 +142,7 @@ static int get_smb_linux_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA try to get the disk space from disk quotas (LINUX version) ****************************************************************************/ -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { int r; SMB_STRUCT_STAT S; @@ -156,7 +182,10 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U save_re_uid(); set_effective_uid(0); - r=get_smb_linux_quota(mnt->mnt_fsname, euser_id, &D); + if (strcmp(mnt->mnt_type, "xfs") == 0) + r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D); + else + r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D); restore_re_uid(); /* Use softlimit to determine disk space, except when it has been exceeded */ @@ -201,7 +230,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U try to get the disk space from disk quotas (CRAY VERSION) ****************************************************************************/ -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { struct mntent *mnt; FILE *fd; @@ -481,7 +510,7 @@ try to get the disk space from disk quotas (SunOS & Solaris2 version) Quota code by Peter Urbanec (amiga@cse.unsw.edu.au). ****************************************************************************/ -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { uid_t euser_id; int ret; @@ -641,7 +670,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U try to get the disk space from disk quotas - OSF1 version ****************************************************************************/ -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { int r, save_errno; struct dqblk D; @@ -707,7 +736,7 @@ try to get the disk space from disk quotas (IRIX 6.2 version) #include <sys/quota.h> #include <mntent.h> -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { uid_t euser_id; int r; @@ -845,7 +874,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U try to get the disk space from disk quotas - default version ****************************************************************************/ -BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { int r; struct dqblk D; diff --git a/source/smbd/reply.c b/source/smbd/reply.c index ffcbe6d8986..0d89adf25b6 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -28,7 +28,6 @@ /* look in server.c for some explanation of these variables */ extern int Protocol; -extern int DEBUGLEVEL; extern int max_send; extern int max_recv; extern char magic_char; @@ -80,8 +79,8 @@ int reply_special(char *inbuf,char *outbuf) switch (msg_type) { case 0x81: /* session request */ - CVAL(outbuf,0) = 0x82; - CVAL(outbuf,3) = 0; + SCVAL(outbuf,0,0x82); + SCVAL(outbuf,3,0); if (name_len(inbuf+4) > 50 || name_len(inbuf+4 + name_len(inbuf + 4)) > 50) { DEBUG(0,("Invalid name length in session request\n")); @@ -114,7 +113,7 @@ int reply_special(char *inbuf,char *outbuf) if (name_type == 'R') { /* We are being asked for a pathworks session --- no thanks! */ - CVAL(outbuf, 0) = 0x83; + SCVAL(outbuf, 0, 0x83); break; } @@ -127,16 +126,15 @@ int reply_special(char *inbuf,char *outbuf) reload_services(True); reopen_logs(); - if (lp_status(-1)) { - claim_connection(NULL,"",MAXSTATUS,True); - } + if (lp_status(-1)) + claim_connection(NULL,"",0,True); break; case 0x89: /* session keepalive request (some old clients produce this?) */ - CVAL(outbuf,0) = 0x85; - CVAL(outbuf,3) = 0; + SCVAL(outbuf,0,0x85); + SCVAL(outbuf,3,0); break; case 0x82: /* positive session response */ @@ -161,12 +159,12 @@ int reply_special(char *inbuf,char *outbuf) work out what error to give to a failed connection ********************************************************************/ -static int connection_error(char *inbuf,char *outbuf,int ecode) +static int connection_error(char *outbuf, int ecode) { if (ecode == ERRnoipc || ecode == ERRnosuchshare) - return(ERROR(ERRDOS,ecode)); - - return(ERROR(ERRSRV,ecode)); + return(ERROR_DOS(ERRDOS,ecode)); + + return(ERROR_DOS(ERRSRV,ecode)); } /**************************************************************************** @@ -258,7 +256,7 @@ int reply_tcon(connection_struct *conn, if (!conn) { END_PROFILE(SMBtcon); - return(connection_error(inbuf,outbuf,ecode)); + return(connection_error(outbuf,ecode)); } outsize = set_message(outbuf,2,0,True); @@ -300,7 +298,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (passlen > MAX_PASS_LEN) { overflow_attack(passlen); - return(ERROR(ERRDOS,ERRbuftoosmall)); + return(ERROR_DOS(ERRDOS,ERRbuftoosmall)); } memcpy(password,smb_buf(inbuf),passlen); @@ -321,7 +319,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt p = strchr(path+2,'\\'); if (!p) { END_PROFILE(SMBtconX); - return(ERROR(ERRDOS,ERRnosuchshare)); + return(ERROR_DOS(ERRDOS,ERRnosuchshare)); } fstrcpy(service,p+1); } @@ -368,7 +366,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (!conn) { END_PROFILE(SMBtconX); - return(connection_error(inbuf,outbuf,ecode)); + return(connection_error(outbuf,ecode)); } if (Protocol < PROTOCOL_NT1) { @@ -416,7 +414,7 @@ int reply_unknown(char *inbuf,char *outbuf) DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n", smb_fn_name(type), type, type)); - return(ERROR(ERRSRV,ERRunknownsmb)); + return(ERROR_DOS(ERRSRV,ERRunknownsmb)); } /**************************************************************************** @@ -442,7 +440,7 @@ int reply_ioctl(connection_struct *conn, break; default: END_PROFILE(SMBioctl); - return(ERROR(ERRSRV,ERRnosupport)); + return(ERROR_DOS(ERRSRV,ERRnosupport)); } outsize = set_message(outbuf,8,replysize+1,True); @@ -466,7 +464,6 @@ int reply_ioctl(connection_struct *conn, /**************************************************************************** Always return an error: it's just a matter of which one... - FIXME: memory leak - no call to pdb_free_sam() --jerry ****************************************************************************/ static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user, @@ -491,32 +488,38 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out } else { if ((smb_passlen != 24) || (smb_nt_passlen != 24)) { DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user)); + pdb_free_sam(sam_trust_acct); return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw)); } if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) { DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user)); + pdb_free_sam(sam_trust_acct); return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw)); } acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct); if (acct_ctrl & ACB_DOMTRUST) { DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user)); + pdb_free_sam(sam_trust_acct); return(ERROR_BOTH(NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,ERRDOS,1807)); } if (acct_ctrl & ACB_SVRTRUST) { DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user)); + pdb_free_sam(sam_trust_acct); return(ERROR_BOTH(NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT,ERRDOS,1809)); } if (acct_ctrl & ACB_WSTRUST) { DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user)); + pdb_free_sam(sam_trust_acct); return(ERROR_BOTH(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,ERRDOS,1808)); } } /* don't know what to do: indicate logon failure */ + pdb_free_sam(sam_trust_acct); return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRDOS,1326)); } @@ -526,17 +529,18 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out int smb_create_user(char *unix_user, char *homedir) { - pstring add_script; - int ret; - - pstrcpy(add_script, lp_adduser_script()); - if (! *add_script) return -1; - all_string_sub(add_script, "%u", unix_user, sizeof(pstring)); - if (homedir) - all_string_sub(add_script, "%H", homedir, sizeof(pstring)); - ret = smbrun(add_script,NULL); - DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret)); - return ret; + pstring add_script; + int ret; + + pstrcpy(add_script, lp_adduser_script()); + if (! *add_script) + return -1; + all_string_sub(add_script, "%u", unix_user, sizeof(pstring)); + if (homedir) + all_string_sub(add_script, "%H", homedir, sizeof(pstring)); + ret = smbrun(add_script,NULL); + DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret)); + return ret; } /**************************************************************************** @@ -545,15 +549,16 @@ int smb_create_user(char *unix_user, char *homedir) static int smb_delete_user(char *unix_user) { - pstring del_script; - int ret; - - pstrcpy(del_script, lp_deluser_script()); - if (! *del_script) return -1; - all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); - ret = smbrun(del_script,NULL); - DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); - return ret; + pstring del_script; + int ret; + + pstrcpy(del_script, lp_deluser_script()); + if (! *del_script) + return -1; + all_string_sub(del_script, "%u", unix_user, sizeof(pstring)); + ret = smbrun(del_script,NULL); + DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); + return ret; } /**************************************************************************** @@ -611,19 +616,6 @@ static BOOL check_server_security(char *orig_user, char *domain, char *unix_user if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) smb_create_user(unix_user, NULL); - - if(lp_adduser_script() && pwd) { - SMB_STRUCT_STAT st; - - /* - * Also call smb_create_user if the users home directory - * doesn't exist. Used with winbindd to allow the script to - * create the home directory for a user mapped with winbindd. - */ - - if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) - smb_create_user(unix_user, pwd->pw_dir); - } } return ret; @@ -635,7 +627,7 @@ static BOOL check_server_security(char *orig_user, char *domain, char *unix_user static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user, char *smb_apasswd, int smb_apasslen, - char *smb_ntpasswd, int smb_ntpasslen) + char *smb_ntpasswd, int smb_ntpasslen, NT_USER_TOKEN **pptoken) { BOOL ret = False; BOOL user_exists = True; @@ -650,7 +642,7 @@ static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user ret = domain_client_validate(orig_user, domain, smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen, - &user_exists); + &user_exists, pptoken); if(ret) { /* @@ -712,6 +704,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int static BOOL done_sesssetup = False; BOOL doencrypt = SMBENCRYPT(); fstring domain; + NT_USER_TOKEN *ptok = NULL; + START_PROFILE(SMBsesssetupX); *smb_apasswd = 0; @@ -724,7 +718,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int smb_apasslen = SVAL(inbuf,smb_vwv7); if (smb_apasslen > MAX_PASS_LEN) { overflow_attack(smb_apasslen); - return(ERROR(ERRDOS,ERRbuftoosmall)); + return(ERROR_DOS(ERRDOS,ERRbuftoosmall)); } memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen); @@ -764,7 +758,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int if (passlen1 > MAX_PASS_LEN) { overflow_attack(passlen1); - return(ERROR(ERRDOS,ERRbuftoosmall)); + return(ERROR_DOS(ERRDOS,ERRbuftoosmall)); } passlen1 = MIN(passlen1, MAX_PASS_LEN); @@ -887,7 +881,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int if (!*user && !*smb_apasswd && !*domain) { DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n")); END_PROFILE(SMBsesssetupX); - return(ERROR(ERRDOS,ERRnoaccess)); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); } } @@ -950,7 +944,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int if (!guest && !check_server_security(orig_user, domain, user, smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) && !check_domain_security(orig_user, domain, user, smb_apasswd, - smb_apasslen, smb_ntpasswd, smb_ntpasslen) && + smb_apasslen, smb_ntpasswd, smb_ntpasslen, &ptok) && !check_hosts_equiv(user)) { @@ -992,6 +986,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int { if (lp_map_to_guest() == NEVER_MAP_TO_GUEST) { + delete_nt_token(&ptok); DEBUG(1,("Rejecting user '%s': authentication failed\n", user)); END_PROFILE(SMBsesssetupX); return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); @@ -1001,6 +996,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int { if (smb_getpwnam(user,True)) { + delete_nt_token(&ptok); DEBUG(1,("Rejecting user '%s': bad password\n", user)); END_PROFILE(SMBsesssetupX); return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); @@ -1029,7 +1025,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int if (!strequal(user,lp_guestaccount(-1)) && lp_servicenumber(user) < 0) { - add_home_service(user,get_user_home_dir(user)); + add_home_service(user,get_user_service_home_dir(user)); } @@ -1054,6 +1050,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int { const struct passwd *pw = smb_getpwnam(user,False); if (!pw) { + delete_nt_token(&ptok); DEBUG(1,("Username %s is invalid on this system\n",user)); END_PROFILE(SMBsesssetupX); return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); @@ -1068,13 +1065,14 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int /* register the name and uid as being validated, so further connections to a uid can get through without a password, on the same VC */ - sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest); + sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest,&ptok); + + delete_nt_token(&ptok); if (sess_vuid == -1) { - return(ERROR(ERRDOS,ERRnoaccess)); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); } - SSVAL(outbuf,smb_uid,sess_vuid); SSVAL(inbuf,smb_uid,sess_vuid); @@ -1116,29 +1114,16 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size ok = S_ISDIR(sbuf.st_mode); } - if (!ok) - { + if (!ok) { /* We special case this - as when a Windows machine is parsing a path is steps through the components one at a time - if a component fails it expects ERRbadpath, not ERRbadfile. */ - if(errno == ENOENT) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; + if(errno == ENOENT) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); } -#if 0 - /* Ugly - NT specific hack - maybe not needed ? (JRA) */ - if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && - (get_remote_arch() == RA_WINNT)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbaddirectory; - } -#endif - return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -1201,12 +1186,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (!ok) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - + set_bad_path_error(errno, bad_path); END_PROFILE(SMBgetatr); return(UNIXERROR(ERRDOS,ERRbadfile)); } @@ -1221,11 +1201,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SIVAL(outbuf,smb_vwv3,(uint32)size); if (Protocol >= PROTOCOL_NT1) { - char *p = strrchr(fname,'/'); - uint16 flg2 = SVAL(outbuf,smb_flg2); - if (!p) p = fname; - if (!is_8_3(fname, True)) - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ + SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */ } DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) ); @@ -1264,12 +1240,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (!ok) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - + set_bad_path_error(errno, bad_path); END_PROFILE(SMBsetatr); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1387,7 +1358,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (strlen(directory) == 0) pstrcpy(directory,"./"); memset((char *)status,'\0',21); - CVAL(status,0) = dirtype; + SCVAL(status,0,dirtype); } else { @@ -1413,16 +1384,12 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size { if(dptr_num == -2) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - END_PROFILE(SMBsearch); + set_bad_path_error(errno, bad_path); + END_PROFILE(SMBsearch); return (UNIXERROR(ERRDOS,ERRnofids)); } END_PROFILE(SMBsearch); - return(ERROR(ERRDOS,ERRnofids)); + return ERROR_DOS(ERRDOS,ERRnofids); } dptr_set_wcard(dptr_num, strdup(mask)); } @@ -1471,7 +1438,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if ( (numentries == 0) || !ok) { - CVAL(outbuf,smb_rcls) = ERRDOS; + SCVAL(outbuf,smb_rcls,ERRDOS); SSVAL(outbuf,smb_err,ERRnofiles); dptr_close(&dptr_num); } @@ -1482,7 +1449,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if(ok && expect_close && numentries == 0 && status_len == 0) { - CVAL(outbuf,smb_rcls) = ERRDOS; + SCVAL(outbuf,smb_rcls,ERRDOS); SSVAL(outbuf,smb_err,ERRnofiles); /* Also close the dptr - we know it's gone */ dptr_close(&dptr_num); @@ -1494,12 +1461,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SSVAL(outbuf,smb_vwv0,numentries); SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE); - CVAL(smb_buf(outbuf),0) = 5; + SCVAL(smb_buf(outbuf),0,5); SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE); if (Protocol >= PROTOCOL_NT1) { - uint16 flg2 = SVAL(outbuf,smb_flg2); - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ + SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */ } outsize += DIR_STRUCT_SIZE*numentries; @@ -1536,7 +1502,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (status_len == 0) { END_PROFILE(SMBfclose); - return(ERROR(ERRSRV,ERRsrverror)); + return ERROR_DOS(ERRSRV,ERRsrverror); } memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21); @@ -1590,11 +1556,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (!fsp) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBopen); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1607,7 +1569,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, DEBUG(3,("attempt to open a directory %s\n",fname)); close_file(fsp,False); END_PROFILE(SMBopen); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } outsize = set_message(outbuf,7,0,True); @@ -1621,11 +1583,11 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SSVAL(outbuf,smb_vwv6,rmode); if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); END_PROFILE(SMBopen); return(outsize); } @@ -1666,7 +1628,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize); } else { END_PROFILE(SMBopenX); - return (ERROR(ERRSRV,ERRaccess)); + return ERROR_DOS(ERRSRV,ERRaccess); } } @@ -1685,11 +1647,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (!fsp) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBopenX); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1700,7 +1658,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (fmode & aDIR) { close_file(fsp,False); END_PROFILE(SMBopenX); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } /* If the caller set the extended oplock request bit @@ -1722,11 +1680,11 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt */ if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } set_message(outbuf,15,0,True); @@ -1824,11 +1782,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (!fsp) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBcreate); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1837,11 +1791,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SSVAL(outbuf,smb_vwv0,fsp->fnum); if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); DEBUG( 2, ( "new file %s\n", fname ) ); DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n", @@ -1898,10 +1852,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, close(tmpfd); if (!fsp) { - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBctemp); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -1923,11 +1874,11 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstrcpy(p,s); if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); DEBUG( 2, ( "created temp file %s\n", fname ) ); DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n", @@ -1937,27 +1888,36 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(outsize); } - /******************************************************************* -check if a user is allowed to delete a file + Check if a user is allowed to delete a file. ********************************************************************/ -static BOOL can_delete(char *fname,connection_struct *conn, int dirtype) + +static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) { - SMB_STRUCT_STAT sbuf; - int fmode; + SMB_STRUCT_STAT sbuf; + int fmode; - if (!CAN_WRITE(conn)) return(False); + if (!CAN_WRITE(conn)) + return NT_STATUS_MEDIA_WRITE_PROTECTED; - if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False); - fmode = dos_mode(conn,fname,&sbuf); - if (fmode & aDIR) return(False); - if (!lp_delete_readonly(SNUM(conn))) { - if (fmode & aRONLY) return(False); - } - if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) - return(False); - if (!check_file_sharing(conn,fname,False)) return(False); - return(True); + if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + + fmode = dos_mode(conn,fname,&sbuf); + if (fmode & aDIR) + return NT_STATUS_FILE_IS_A_DIRECTORY; + if (!lp_delete_readonly(SNUM(conn))) { + if (fmode & aRONLY) + return NT_STATUS_CANNOT_DELETE; + } + + if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) + return NT_STATUS_CANNOT_DELETE; + + if (!check_file_sharing(conn,fname,False)) + return NT_STATUS_SHARING_VIOLATION; + + return NT_STATUS_OK; } /**************************************************************************** @@ -1965,14 +1925,13 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype) code. ****************************************************************************/ -int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf, - int dirtype, char *name) +NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) { pstring directory; pstring mask; char *p; int count=0; - int error = ERRnoaccess; + NTSTATUS error = NT_STATUS_OK; BOOL has_wild; BOOL exists=False; BOOL bad_path = False; @@ -2010,8 +1969,12 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf, if (!has_wild) { pstrcat(directory,"/"); pstrcat(directory,mask); - if (can_delete(directory,conn,dirtype) && !vfs_unlink(conn,directory)) + error = can_delete(directory,conn,dirtype); + if (!NT_STATUS_IS_OK(error)) return error; + + if (vfs_unlink(conn,directory) == 0) { count++; + } if (!count) exists = vfs_file_exist(conn,directory,&sbuf); } else { @@ -2026,43 +1989,33 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf, We don't implement this yet XXXX */ - if (dirptr) - { - error = ERRbadfile; + if (dirptr) { + error = NT_STATUS_OBJECT_NAME_NOT_FOUND; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); - while ((dname = ReadDirName(dirptr))) - { + while ((dname = ReadDirName(dirptr))) { pstring fname; pstrcpy(fname,dname); if(!mask_match(fname, mask, case_sensitive)) continue; - error = ERRnoaccess; slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - if (!can_delete(fname,conn,dirtype)) continue; - if (!vfs_unlink(conn,fname)) count++; + error = can_delete(fname,conn,dirtype); + if (!NT_STATUS_IS_OK(error)) continue; + if (vfs_unlink(conn,fname) == 0) count++; DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); } CloseDir(dirptr); } } - if (count == 0) { - if (exists) - return(ERROR(ERRDOS,error)); - else { - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,error)); - } + if (count == 0 && NT_STATUS_IS_OK(error)) { + error = map_nt_error_from_unix(errno); } - return 0; + return error; } /**************************************************************************** @@ -2074,6 +2027,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int outsize = 0; pstring name; int dirtype; + NTSTATUS status; START_PROFILE(SMBunlink); dirtype = SVAL(inbuf,smb_vwv0); @@ -2084,8 +2038,8 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size DEBUG(3,("reply_unlink : %s\n",name)); - outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name); - if(outsize == 0) { + status = unlink_internals(conn, dirtype, name); + if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); /* * Win2k needs a changenotify request response before it will @@ -2095,10 +2049,9 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size process_pending_change_notify_queue((time_t)0); outsize = set_message(outbuf,0,0,True); - } END_PROFILE(SMBunlink); - return(outsize); + return outsize; } /**************************************************************************** @@ -2108,7 +2061,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size void fail_readraw(void) { pstring errstr; - slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)\n", + slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)", strerror(errno) ); exit_server(errstr); } @@ -2119,7 +2072,7 @@ void fail_readraw(void) int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize) { - size_t maxcount,mincount; + ssize_t maxcount,mincount; size_t nread = 0; SMB_OFF_T startpos; char *header = outbuf; @@ -2210,9 +2163,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s if (size < sizeneeded) { SMB_STRUCT_STAT st; if (vfs_fstat(fsp,fsp->fd,&st) == 0) - size = st.st_size; - if (!fsp->can_write) - fsp->size = size; + fsp->size = size = st.st_size; } if (startpos >= size) @@ -2253,8 +2204,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length int outsize = 0; SMB_OFF_T startpos; size_t numtoread; - int eclass; - uint32 ecode; + NTSTATUS status; files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBlockread); @@ -2277,8 +2227,11 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length * for a write lock. JRA. */ - if(!do_lock( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) { - if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) { + status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), + (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK); + + if (NT_STATUS_V(status)) { + if (lp_blocking_locks(SNUM(conn))) { /* * A blocking lock was requested. Package up * this smb into a queued request and push it @@ -2289,7 +2242,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length return -1; } END_PROFILE(SMBlockread); - return (ERROR(eclass,ecode)); + return ERROR_NT(status); } nread = read_file(fsp,data,startpos,numtoread); @@ -2338,7 +2291,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { END_PROFILE(SMBread); - return(ERROR(ERRDOS,ERRlock)); + return ERROR_DOS(ERRDOS,ERRlock); } if (numtoread > 0) @@ -2352,7 +2305,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int outsize += nread; SSVAL(outbuf,smb_vwv0,nread); SSVAL(outbuf,smb_vwv5,nread+3); - CVAL(smb_buf(outbuf),0) = 1; + SCVAL(smb_buf(outbuf),0,1); SSVAL(smb_buf(outbuf),1,nread); DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", @@ -2405,7 +2358,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \ 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) )); END_PROFILE(SMBreadX); - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); } #endif /* LARGE_SMB_OFF_T */ @@ -2414,7 +2367,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { END_PROFILE(SMBreadX); - return(ERROR(ERRDOS,ERRlock)); + return ERROR_DOS(ERRDOS,ERRlock); } nread = read_file(fsp,data,startpos,smb_maxcnt); @@ -2470,12 +2423,12 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, } /* force the error type */ - CVAL(inbuf,smb_com) = SMBwritec; - CVAL(outbuf,smb_com) = SMBwritec; + SCVAL(inbuf,smb_com,SMBwritec); + SCVAL(outbuf,smb_com,SMBwritec); if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwritebraw); - return(ERROR(ERRDOS,ERRlock)); + return(ERROR_DOS(ERRDOS,ERRlock)); } if (numtowrite>0) @@ -2492,11 +2445,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, total_written = nwritten; /* Return a message to the redirector to tell it to send more bytes */ - CVAL(outbuf,smb_com) = SMBwritebraw; + SCVAL(outbuf,smb_com,SMBwritebraw); SSVALS(outbuf,smb_vwv0,-1); outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_writebraw: send_smb failed.\n"); + exit_server("reply_writebraw: send_smb failed."); /* Now read the raw data into the buffer and write it */ if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) { @@ -2508,7 +2461,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, /* Set up outbuf to return the correct return */ outsize = set_message(outbuf,1,0,True); - CVAL(outbuf,smb_com) = SMBwritec; + SCVAL(outbuf,smb_com,SMBwritec); SSVAL(outbuf,smb_vwv0,total_written); if (numtowrite != 0) { @@ -2533,7 +2486,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite); if (nwritten < (ssize_t)numtowrite) { - CVAL(outbuf,smb_rcls) = ERRHRD; + SCVAL(outbuf,smb_rcls,ERRHRD); SSVAL(outbuf,smb_err,ERRdiskfull); } @@ -2572,8 +2525,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz size_t numtowrite; SMB_OFF_T startpos; char *data; - int eclass; - uint32 ecode; + NTSTATUS status; files_struct *fsp = file_fsp(inbuf,smb_vwv0); int outsize = 0; START_PROFILE(SMBwriteunlock); @@ -2585,9 +2537,10 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz startpos = IVAL(inbuf,smb_vwv2); data = smb_buf(inbuf) + 3; - if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { + if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, + WRITE_LOCK,False)) { END_PROFILE(SMBwriteunlock); - return(ERROR(ERRDOS,ERRlock)); + return ERROR_DOS(ERRDOS,ERRlock); } /* The special X/Open SMB protocol handling of @@ -2606,9 +2559,11 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz return(UNIXERROR(ERRDOS,ERRnoaccess)); } - if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode)) { + status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, + (SMB_BIG_UINT)startpos); + if (NT_STATUS_V(status)) { END_PROFILE(SMBwriteunlock); - return(ERROR(eclass,ecode)); + return ERROR_NT(status); } outsize = set_message(outbuf,1,0,True); @@ -2622,27 +2577,6 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz return(outsize); } -/**************************************************************************** - Return correct error for space allocation fail. -****************************************************************************/ - -int allocate_space_error(char *inbuf,char *outbuf, int errno_val) -{ - errno = errno_val; - if (!(global_client_caps & CAP_STATUS32)) - return (UNIXERROR(ERRHRD,ERRdiskfull)); - - /* Use more specific WNT/W2K error codes. */ -#ifdef EDQUOT - if (errno_val == ENOSPC || errno_val == EDQUOT) { -#else - if (errno_val == ENOSPC) { -#endif - return(ERROR(0,NT_STATUS_DISK_FULL)); - } - - return (UNIXERROR(ERRHRD,ERRdiskfull)); -} /**************************************************************************** Reply to a write. @@ -2650,68 +2584,76 @@ int allocate_space_error(char *inbuf,char *outbuf, int errno_val) int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize) { - size_t numtowrite; - ssize_t nwritten = -1; - SMB_OFF_T startpos; - char *data; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - int outsize = 0; - START_PROFILE(SMBwrite); + size_t numtowrite; + ssize_t nwritten = -1; + SMB_OFF_T startpos; + char *data; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + int outsize = 0; + START_PROFILE(SMBwrite); - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - END_PROFILE(SMBwrite); - return reply_pipe_write(inbuf,outbuf,size,dum_buffsize); - } + /* If it's an IPC, pass off the pipe handler. */ + if (IS_IPC(conn)) { + END_PROFILE(SMBwrite); + return reply_pipe_write(inbuf,outbuf,size,dum_buffsize); + } - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + CHECK_FSP(fsp,conn); + CHECK_WRITE(fsp); - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - data = smb_buf(inbuf) + 3; + numtowrite = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); + data = smb_buf(inbuf) + 3; - if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { - END_PROFILE(SMBwrite); - return(ERROR(ERRDOS,ERRlock)); - } + if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { + END_PROFILE(SMBwrite); + return ERROR_DOS(ERRDOS,ERRlock); + } - /* X/Open SMB protocol says that if smb_vwv1 is - zero then the file size should be extended or - truncated to the size given in smb_vwv[2-3] */ - if(numtowrite == 0) { - /* This is actually an allocate call, not set EOF. JRA */ - nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos); - if (nwritten < 0) { - int ret = allocate_space_error(inbuf, outbuf, errno); - END_PROFILE(SMBwrite); - return ret; - } - } else - nwritten = write_file(fsp,data,startpos,numtowrite); + /* + * X/Open SMB protocol says that if smb_vwv1 is + * zero then the file size should be extended or + * truncated to the size given in smb_vwv[2-3]. + */ + + if(numtowrite == 0) { + /* + * This is actually an allocate call, and set EOF. JRA. + */ + nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos); + if (nwritten < 0) { + END_PROFILE(SMBwrite); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos); + if (nwritten < 0) { + END_PROFILE(SMBwrite); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + } else + nwritten = write_file(fsp,data,startpos,numtowrite); - if (lp_syncalways(SNUM(conn))) - sync_file(conn,fsp); + if (lp_syncalways(SNUM(conn))) + sync_file(conn,fsp); - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - END_PROFILE(SMBwrite); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { + END_PROFILE(SMBwrite); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - outsize = set_message(outbuf,1,0,True); + outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,nwritten); + SSVAL(outbuf,smb_vwv0,nwritten); - if (nwritten < (ssize_t)numtowrite) { - CVAL(outbuf,smb_rcls) = ERRHRD; - SSVAL(outbuf,smb_err,ERRdiskfull); - } + if (nwritten < (ssize_t)numtowrite) { + SCVAL(outbuf,smb_rcls,ERRHRD); + SSVAL(outbuf,smb_err,ERRdiskfull); + } - DEBUG(3,("write fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten)); + DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten)); - END_PROFILE(SMBwrite); - return(outsize); + END_PROFILE(SMBwrite); + return(outsize); } @@ -2746,7 +2688,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) { END_PROFILE(SMBwriteX); - return(ERROR(ERRDOS,ERRbadmem)); + return ERROR_DOS(ERRDOS,ERRbadmem); } data = smb_base(inbuf) + smb_doff; @@ -2768,7 +2710,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \ 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) )); END_PROFILE(SMBwriteX); - return(ERROR(ERRDOS,ERRbadaccess)); + return ERROR_DOS(ERRDOS,ERRbadaccess); } #endif /* LARGE_SMB_OFF_T */ @@ -2776,7 +2718,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwriteX); - return(ERROR(ERRDOS,ERRlock)); + return ERROR_DOS(ERRDOS,ERRlock); } /* X/Open SMB protocol says that, unlike SMBwrite @@ -2800,7 +2742,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1); if (nwritten < (ssize_t)numtowrite) { - CVAL(outbuf,smb_rcls) = ERRHRD; + SCVAL(outbuf,smb_rcls,ERRHRD); SSVAL(outbuf,smb_err,ERRdiskfull); } @@ -2963,7 +2905,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, if(!fsp || (fsp->conn != conn)) { END_PROFILE(SMBclose); - return(ERROR(ERRDOS,ERRbadfid)); + return ERROR_DOS(ERRDOS,ERRbadfid); } if(fsp->is_directory || fsp->stat_open) { @@ -2978,21 +2920,10 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, * Close ordinary file. */ int close_err; + pstring file_name; - /* - * If there was a modify time outstanding, - * try and set it here. - */ - if(fsp->pending_modtime) - set_filetime(conn, fsp->fsp_name, fsp->pending_modtime); - - /* - * Now take care of any time sent in the close. - */ - mtime = make_unix_date3(inbuf+smb_vwv1); - - /* try and set the date */ - set_filetime(conn, fsp->fsp_name,mtime); + /* Save the name for time set in close. */ + pstrcpy( file_name, fsp->fsp_name); DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n", fsp->fd, fsp->fnum, @@ -3009,6 +2940,16 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, END_PROFILE(SMBclose); return (UNIXERROR(ERRHRD,ERRgeneral)); } + + /* + * Now take care of any time sent in the close. + */ + + mtime = make_unix_date3(inbuf+smb_vwv1); + + /* try and set the date */ + set_filetime(conn, file_name, mtime); + } END_PROFILE(SMBclose); @@ -3043,7 +2984,7 @@ int reply_writeclose(connection_struct *conn, if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { END_PROFILE(SMBwriteclose); - return(ERROR(ERRDOS,ERRlock)); + return ERROR_DOS(ERRDOS,ERRlock); } nwritten = write_file(fsp,data,startpos,numtowrite); @@ -3083,8 +3024,7 @@ int reply_lock(connection_struct *conn, { int outsize = set_message(outbuf,0,0,True); SMB_BIG_UINT count,offset; - int eclass; - uint32 ecode; + NTSTATUS status; files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBlock); @@ -3098,8 +3038,9 @@ int reply_lock(connection_struct *conn, DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n", fsp->fd, fsp->fnum, (double)offset, (double)count)); - if (!do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &eclass, &ecode)) { - if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) { + status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK); + if (NT_STATUS_V(status)) { + if (lp_blocking_locks(SNUM(conn))) { /* * A blocking lock was requested. Package up * this smb into a queued request and push it @@ -3111,7 +3052,7 @@ int reply_lock(connection_struct *conn, } } END_PROFILE(SMBlock); - return (ERROR(eclass,ecode)); + return ERROR_NT(status); } END_PROFILE(SMBlock); @@ -3126,8 +3067,7 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, in { int outsize = set_message(outbuf,0,0,True); SMB_BIG_UINT count,offset; - int eclass; - uint32 ecode; + NTSTATUS status; files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBunlock); @@ -3136,9 +3076,10 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, in count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1); offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3); - if(!do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, &eclass, &ecode)) { + status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset); + if (NT_STATUS_V(status)) { END_PROFILE(SMBunlock); - return (ERROR(eclass,ecode)); + return ERROR_NT(status); } DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n", @@ -3164,7 +3105,7 @@ int reply_tdis(connection_struct *conn, if (!conn) { DEBUG(4,("Invalid connection in tdis\n")); END_PROFILE(SMBtdis); - return(ERROR(ERRSRV,ERRinvnid)); + return ERROR_DOS(ERRSRV,ERRinvnid); } conn->used = False; @@ -3206,7 +3147,7 @@ int reply_echo(connection_struct *conn, smb_setlen(outbuf,outsize - 4); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_echo: send_smb failed.\n"); + exit_server("reply_echo: send_smb failed."); } DEBUG(3,("echo %d times\n", smb_reverb)); @@ -3230,11 +3171,11 @@ int reply_printopen(connection_struct *conn, if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplopen); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } /* Open for exclusive use, write only. */ - fsp = print_fsp_open(conn); + fsp = print_fsp_open(conn, NULL); if (!fsp) { END_PROFILE(SMBsplopen); @@ -3267,7 +3208,7 @@ int reply_printclose(connection_struct *conn, if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplclose); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } DEBUG(3,("printclose fd=%d fnum=%d\n", @@ -3303,12 +3244,12 @@ int reply_printqueue(connection_struct *conn, get it right (tridge) */ if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplretq); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } SSVAL(outbuf,smb_vwv0,0); SSVAL(outbuf,smb_vwv1,0); - CVAL(smb_buf(outbuf),0) = 1; + SCVAL(smb_buf(outbuf),0,1); SSVAL(smb_buf(outbuf),1,0); DEBUG(3,("printqueue start_index=%d max_count=%d\n", @@ -3316,8 +3257,9 @@ int reply_printqueue(connection_struct *conn, { print_queue_struct *queue = NULL; + print_status_struct status; char *p = smb_buf(outbuf) + 3; - int count = print_queue_status(SNUM(conn), &queue,NULL); + int count = print_queue_status(SNUM(conn), &queue, &status); int num_to_get = ABS(max_count); int first = (max_count>0?start_index:start_index+max_count+1); int i; @@ -3330,10 +3272,10 @@ int reply_printqueue(connection_struct *conn, for (i=first;i<first+num_to_get;i++) { put_dos_date2(p,0,queue[i].time); - CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3); + SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3)); SSVAL(p,5, queue[i].job); SIVAL(p,7,queue[i].size); - CVAL(p,11) = 0; + SCVAL(p,11,0); StrnCpy(p+12,queue[i].user,16); p += 28; } @@ -3342,11 +3284,11 @@ int reply_printqueue(connection_struct *conn, outsize = set_message(outbuf,2,28*count+3,False); SSVAL(outbuf,smb_vwv0,count); SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1)); - CVAL(smb_buf(outbuf),0) = 1; + SCVAL(smb_buf(outbuf),0,1); SSVAL(smb_buf(outbuf),1,28*count); } - if (queue) free(queue); + SAFE_FREE(queue); DEBUG(3,("%d entries returned in queue\n",count)); } @@ -3369,7 +3311,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplwr); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } CHECK_FSP(fsp,conn); @@ -3394,7 +3336,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ The guts of the mkdir command, split out so it may be called by the NT SMB code. ****************************************************************************/ -int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory) +NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) { BOOL bad_path = False; SMB_STRUCT_STAT sbuf; @@ -3405,34 +3347,31 @@ int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring d if (check_name(directory, conn)) ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); - if (ret < 0) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); + if (ret == -1) { + return map_nt_error_from_unix(errno); } - return ret; + return NT_STATUS_OK; } /**************************************************************************** - Reply to a mkdir + Reply to a mkdir. ****************************************************************************/ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring directory; int outsize; + NTSTATUS status; START_PROFILE(SMBmkdir); pstrcpy(directory,smb_buf(inbuf) + 1); - outsize=mkdir_internal(conn, inbuf, outbuf, directory); - if(outsize == 0) - outsize = set_message(outbuf,0,0,True); + status = mkdir_internal(conn, directory); + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); + + outsize = set_message(outbuf,0,0,True); DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) ); @@ -3600,11 +3539,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (!ok) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); END_PROFILE(SMBrmdir); return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -3683,26 +3618,26 @@ static BOOL resolve_wildcards(char *name1,char *name2) } /******************************************************************* -check if a user is allowed to rename a file + Check if a user is allowed to rename a file. ********************************************************************/ -static BOOL can_rename(char *fname,connection_struct *conn) + +static NTSTATUS can_rename(char *fname,connection_struct *conn) { - SMB_STRUCT_STAT sbuf; + if (!CAN_WRITE(conn)) + return NT_STATUS_ACCESS_DENIED; - if (!CAN_WRITE(conn)) return(False); + if (!check_file_sharing(conn,fname,True)) + return NT_STATUS_SHARING_VIOLATION; - if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False); - if (!check_file_sharing(conn,fname,True)) return(False); - return(True); + return NT_STATUS_OK; } /**************************************************************************** The guts of the rename command, split out so it may be called by the NT SMB code. ****************************************************************************/ -int rename_internals(connection_struct *conn, - char *inbuf, char *outbuf, char *name, - char *newname, BOOL replace_if_exists) + +NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists) { pstring directory; pstring mask; @@ -3712,11 +3647,9 @@ int rename_internals(connection_struct *conn, BOOL bad_path1 = False; BOOL bad_path2 = False; int count=0; - int error = ERRnoaccess; - BOOL exists=False; + NTSTATUS error = NT_STATUS_OK; BOOL rc = True; SMB_STRUCT_STAT sbuf1, sbuf2; - pstring zdirectory; *directory = *mask = 0; @@ -3758,6 +3691,9 @@ int rename_internals(connection_struct *conn, has_wild = ms_has_wild(mask); if (!has_wild) { + pstring zdirectory; + pstring znewname; + /* * No wildcards - just process the one file. */ @@ -3776,7 +3712,8 @@ int rename_internals(connection_struct *conn, pstrcpy(newname, tmpstr); } - DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", + DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \ +directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", case_sensitive, case_preserve, short_case_preserve, directory, newname, newname_last_component, is_short_name)); @@ -3814,37 +3751,82 @@ int rename_internals(connection_struct *conn, } } - pstrcpy(zdirectory, dos_to_unix(directory, False)); - if(replace_if_exists) { - /* - * NT SMB specific flag - rename can overwrite - * file with the same name so don't check for - * vfs_file_exist(). - */ - if(resolve_wildcards(directory,newname) && - can_rename(directory,conn) && - !conn->vfs_ops.rename(conn,zdirectory, - dos_to_unix(newname,False))) - count++; - } else { - if (resolve_wildcards(directory,newname) && - can_rename(directory,conn) && - !vfs_file_exist(conn,newname,NULL) && - !conn->vfs_ops.rename(conn,zdirectory, - dos_to_unix(newname,False))) - count++; + resolve_wildcards(directory,newname); + + /* + * The source object must exist. + */ + + if (!vfs_object_exist(conn, directory, NULL)) { + DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n", + directory,newname)); + + if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) { + /* + * Must return different errors depending on whether the parent + * directory existed or not. + */ + + p = strrchr(directory, '/'); + if (!p) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + *p = '\0'; + if (vfs_object_exist(conn, directory, NULL)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + error = map_nt_error_from_unix(errno); + DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", + get_nt_error_msg(error), directory,newname)); + + return error; } - DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed", - directory,newname)); - - if (!count) exists = vfs_file_exist(conn,directory,NULL); - if (!count && exists && vfs_file_exist(conn,newname,NULL)) { - exists = True; - error = ERRrename; + error = can_rename(directory,conn); + + if (!NT_STATUS_IS_OK(error)) { + DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", + get_nt_error_msg(error), directory,newname)); + return error; } + + pstrcpy(zdirectory, dos_to_unix(directory, False)); + pstrcpy(znewname, dos_to_unix(newname,False)); + + /* + * If the src and dest names are identical - including case, + * don't do the rename, just return success. + */ + + if (strcsequal(zdirectory, znewname)) { + DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory)); + return NT_STATUS_OK; + } + + if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) { + DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n", + directory,newname)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + if(conn->vfs_ops.rename(conn,zdirectory, znewname) == 0) { + DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", + directory,newname)); + return NT_STATUS_OK; + } + + if (errno == ENOTDIR || errno == EISDIR) + error = NT_STATUS_OBJECT_NAME_COLLISION; + else + error = map_nt_error_from_unix(errno); + + DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", + get_nt_error_msg(error), directory,newname)); + + return error; } else { + /* * Wildcards - process each file that matches. */ @@ -3856,7 +3838,7 @@ int rename_internals(connection_struct *conn, dirptr = OpenDir(conn, directory, True); if (dirptr) { - error = ERRbadfile; + error = NT_STATUS_OBJECT_NAME_NOT_FOUND; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); @@ -3869,10 +3851,11 @@ int rename_internals(connection_struct *conn, if(!mask_match(fname, mask, case_sensitive)) continue; - error = ERRnoaccess; + error = NT_STATUS_ACCESS_DENIED; slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); - if (!can_rename(fname,conn)) { - DEBUG(6,("rename %s refused\n", fname)); + error = can_rename(fname,conn); + if (!NT_STATUS_IS_OK(error)) { + DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error))); continue; } pstrcpy(destname,newname); @@ -3884,9 +3867,9 @@ int rename_internals(connection_struct *conn, } if (!replace_if_exists && - vfs_file_exist(conn,destname, NULL)) { + vfs_object_exist(conn,destname, NULL)) { DEBUG(6,("file_exist %s\n", destname)); - error = 183; + error = NT_STATUS_OBJECT_NAME_COLLISION; continue; } @@ -3898,20 +3881,12 @@ int rename_internals(connection_struct *conn, CloseDir(dirptr); } } - - if (count == 0) { - if (exists) - return(ERROR(ERRDOS,error)); - else { - if((errno == ENOENT) && (bad_path1 || bad_path2)) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,error)); - } + + if (count == 0 && NT_STATUS_IS_OK(error)) { + error = map_nt_error_from_unix(errno); } - return 0; + return error; } /**************************************************************************** @@ -3920,34 +3895,34 @@ int rename_internals(connection_struct *conn, int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - pstring name; - pstring newname; - START_PROFILE(SMBmv); + int outsize = 0; + pstring name; + pstring newname; + NTSTATUS status; + START_PROFILE(SMBmv); - pstrcpy(name,smb_buf(inbuf) + 1); - pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name)); + pstrcpy(name,smb_buf(inbuf) + 1); + pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name)); - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); + DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - outsize = rename_internals(conn, inbuf, outbuf, name, newname, False); - if(outsize == 0) { + status = rename_internals(conn, name, newname, False); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - - process_pending_change_notify_queue((time_t)0); - - outsize = set_message(outbuf,0,0,True); - } + * Win2k needs a changenotify request response before it will + * update after a rename.. + */ + process_pending_change_notify_queue((time_t)0); + outsize = set_message(outbuf,0,0,True); - END_PROFILE(SMBmv); - return(outsize); + END_PROFILE(SMBmv); + return(outsize); } /******************************************************************* @@ -4014,6 +3989,10 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size); close_file(fsp1,False); + + /* Ensure the modtime is set correctly on the destination file. */ + fsp2->pending_modtime = src_sbuf.st_mtime; + /* * As we are opening fsp1 read-only we only expect * an error on close on fsp2 if we are out of space. @@ -4063,7 +4042,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* can't currently handle inter share copies XXXX */ DEBUG(3,("Rejecting inter-share copy\n")); END_PROFILE(SMBcopy); - return(ERROR(ERRSRV,ERRinvdevice)); + return ERROR_DOS(ERRSRV,ERRinvdevice); } RESOLVE_DFSPATH(name, conn, inbuf, outbuf); @@ -4076,19 +4055,19 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if ((flags&1) && target_is_directory) { END_PROFILE(SMBcopy); - return(ERROR(ERRDOS,ERRbadfile)); + return ERROR_DOS(ERRDOS,ERRbadfile); } if ((flags&2) && !target_is_directory) { END_PROFILE(SMBcopy); - return(ERROR(ERRDOS,ERRbadpath)); + return ERROR_DOS(ERRDOS,ERRbadpath); } if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) { /* wants a tree copy! XXXX */ DEBUG(3,("Rejecting tree copy\n")); END_PROFILE(SMBcopy); - return(ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } p = strrchr(name,'/'); @@ -4170,7 +4149,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, if (exists) { END_PROFILE(SMBcopy); - return(ERROR(ERRDOS,error)); + return ERROR_DOS(ERRDOS,error); } else { if((errno == ENOENT) && (bad_path1 || bad_path2)) @@ -4204,7 +4183,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size snum = SNUM(conn); if (!CAN_SETDIR(snum)) { END_PROFILE(pathworks_setdir); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } pstrcpy(newdir,smb_buf(inbuf) + 1); @@ -4221,11 +4200,11 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (!ok) { END_PROFILE(pathworks_setdir); - return(ERROR(ERRDOS,ERRbadpath)); + return ERROR_DOS(ERRDOS,ERRbadpath); } outsize = set_message(outbuf,0,0,True); - CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh); + SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh)); DEBUG(3,("setdir %s\n", newdir)); @@ -4242,7 +4221,7 @@ uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format) if(!large_file_format) return SVAL(data,SMB_LPID_OFFSET(data_offset)); else - return SVAL(data,SMB_LARGE__LPID_OFFSET(data_offset)); + return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset)); } /**************************************************************************** @@ -4382,10 +4361,10 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, int32 lock_timeout = IVAL(inbuf,smb_vwv4); int i; char *data; - uint32 ecode=0, dummy2; - int eclass=0, dummy1; BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; BOOL err; + NTSTATUS status; + START_PROFILE(SMBlockingX); CHECK_FSP(fsp,conn); @@ -4395,8 +4374,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, /* Check if this is an oplock break on a file we have granted an oplock on. */ - if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) - { + if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) { /* Client can insist on breaking to none. */ BOOL break_to_none = (oplocklevel == 0); @@ -4407,18 +4385,17 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, * Make sure we have granted an exclusive or batch oplock on this file. */ - if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - { + if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); /* if this is a pure oplock break request then don't send a reply */ if (num_locks == 0 && num_ulocks == 0) { - END_PROFILE(SMBlockingX); + END_PROFILE(SMBlockingX); return -1; } else { - END_PROFILE(SMBlockingX); - return ERROR(ERRDOS,ERRlock); + END_PROFILE(SMBlockingX); + return ERROR_DOS(ERRDOS,ERRlock); } } @@ -4428,8 +4405,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); } /* if this is a pure oplock break request then don't send a reply */ - if (num_locks == 0 && num_ulocks == 0) - { + if (num_locks == 0 && num_ulocks == 0) { /* Sanity check - ensure a pure oplock break is not a chained request. */ if(CVAL(inbuf,smb_vwv0) != 0xff) @@ -4459,15 +4435,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); */ if(err) { END_PROFILE(SMBlockingX); - return ERROR(ERRDOS,ERRnoaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n", (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); - if(!do_unlock(fsp,conn,lock_pid,count,offset, &eclass, &ecode)) { + status = do_unlock(fsp,conn,lock_pid,count,offset); + if (NT_STATUS_V(status)) { END_PROFILE(SMBlockingX); - return ERROR(eclass,ecode); + return ERROR_NT(status); } } @@ -4490,15 +4467,16 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); */ if(err) { END_PROFILE(SMBlockingX); - return ERROR(ERRDOS,ERRnoaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n", (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); - if(!do_lock(fsp,conn,lock_pid, count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK), - &eclass, &ecode)) { - if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) { + status = do_lock(fsp,conn,lock_pid, count,offset, + ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); + if (NT_STATUS_V(status)) { + if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) { /* * A blocking lock was requested. Package up * this smb into a queued request and push it @@ -4531,13 +4509,13 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); */ if(err) { END_PROFILE(SMBlockingX); - return ERROR(ERRDOS,ERRnoaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } - do_unlock(fsp,conn,lock_pid,count,offset,&dummy1,&dummy2); + do_unlock(fsp,conn,lock_pid,count,offset); } END_PROFILE(SMBlockingX); - return ERROR(eclass,ecode); + return ERROR_NT(status); } set_message(outbuf,2,0,True); @@ -4549,8 +4527,86 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); return chain_reply(inbuf,outbuf,length,bufsize); } +/* Back from the dead for OS/2..... JRA. */ + /**************************************************************************** - reply to a SMBsetattrE + Reply to a SMBreadbmpx (read block multiplex) request +****************************************************************************/ + +int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) +{ + ssize_t nread = -1; + ssize_t total_read; + char *data; + SMB_OFF_T startpos; + int outsize; + size_t maxcount; + int max_per_packet; + size_t tcount; + int pad; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBreadBmpx); + + /* this function doesn't seem to work - disable by default */ + if (!lp_readbmpx()) { + END_PROFILE(SMBreadBmpx); + return ERROR_DOS(ERRSRV,ERRuseSTD); + } + + outsize = set_message(outbuf,8,0,True); + + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); + CHECK_ERROR(fsp); + + startpos = IVAL(inbuf,smb_vwv1); + maxcount = SVAL(inbuf,smb_vwv3); + + data = smb_buf(outbuf); + pad = ((long)data)%4; + if (pad) + pad = 4 - pad; + data += pad; + + max_per_packet = bufsize-(outsize+pad); + tcount = maxcount; + total_read = 0; + + if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK, False)) { + END_PROFILE(SMBreadBmpx); + return ERROR_DOS(ERRDOS,ERRlock); + } + + do { + size_t N = MIN(max_per_packet,tcount-total_read); + + nread = read_file(fsp,data,startpos,N); + + if (nread <= 0) + nread = 0; + + if (nread < (ssize_t)N) + tcount = total_read + nread; + + set_message(outbuf,8,nread,False); + SIVAL(outbuf,smb_vwv0,startpos); + SSVAL(outbuf,smb_vwv2,tcount); + SSVAL(outbuf,smb_vwv6,nread); + SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf)); + + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("reply_readbmpx: send_smb failed."); + + total_read += nread; + startpos += nread; + } while (total_read < (ssize_t)tcount); + + END_PROFILE(SMBreadBmpx); + return(-1); +} + +/**************************************************************************** + Reply to a SMBsetattrE. ****************************************************************************/ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -4595,7 +4651,7 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, /* Set the date on this file */ if(file_utime(conn, fsp->fsp_name, &unix_times)) { END_PROFILE(SMBsetattrE); - return(ERROR(ERRDOS,ERRnoaccess)); + return ERROR_DOS(ERRDOS,ERRnoaccess); } DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", @@ -4606,8 +4662,199 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, } +/* Back from the dead for OS/2..... JRA. */ + +/**************************************************************************** + Reply to a SMBwritebmpx (write block multiplex primary) request. +****************************************************************************/ + +int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) +{ + size_t numtowrite; + ssize_t nwritten = -1; + int outsize = 0; + SMB_OFF_T startpos; + size_t tcount; + BOOL write_through; + int smb_doff; + char *data; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBwriteBmpx); + + CHECK_FSP(fsp,conn); + CHECK_WRITE(fsp); + CHECK_ERROR(fsp); + + tcount = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv3); + write_through = BITSETW(inbuf+smb_vwv7,0); + numtowrite = SVAL(inbuf,smb_vwv10); + smb_doff = SVAL(inbuf,smb_vwv11); + + data = smb_base(inbuf) + smb_doff; + + /* If this fails we need to send an SMBwriteC response, + not an SMBwritebmpx - set this up now so we don't forget */ + SCVAL(outbuf,smb_com,SMBwritec); + + if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) { + END_PROFILE(SMBwriteBmpx); + return(ERROR_DOS(ERRDOS,ERRlock)); + } + + nwritten = write_file(fsp,data,startpos,numtowrite); + + if(lp_syncalways(SNUM(conn)) || write_through) + sync_file(conn,fsp); + + if(nwritten < (ssize_t)numtowrite) { + END_PROFILE(SMBwriteBmpx); + return(UNIXERROR(ERRHRD,ERRdiskfull)); + } + + /* If the maximum to be written to this file + is greater than what we just wrote then set + up a secondary struct to be attached to this + fd, we will use this to cache error messages etc. */ + + if((ssize_t)tcount > nwritten) { + write_bmpx_struct *wbms; + if(fsp->wbmpx_ptr != NULL) + wbms = fsp->wbmpx_ptr; /* Use an existing struct */ + else + wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct)); + + if(!wbms) { + DEBUG(0,("Out of memory in reply_readmpx\n")); + END_PROFILE(SMBwriteBmpx); + return(ERROR_DOS(ERRSRV,ERRnoresource)); + } + wbms->wr_mode = write_through; + wbms->wr_discard = False; /* No errors yet */ + wbms->wr_total_written = nwritten; + wbms->wr_errclass = 0; + wbms->wr_error = 0; + fsp->wbmpx_ptr = wbms; + } + + /* We are returning successfully, set the message type back to + SMBwritebmpx */ + SCVAL(outbuf,smb_com,SMBwriteBmpx); + + outsize = set_message(outbuf,1,0,True); + + SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */ + + DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n", + fsp->fnum, (int)numtowrite, (int)nwritten ) ); + + if (write_through && tcount==nwritten) { + /* We need to send both a primary and a secondary response */ + smb_setlen(outbuf,outsize - 4); + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("reply_writebmpx: send_smb failed."); + + /* Now the secondary */ + outsize = set_message(outbuf,1,0,True); + SCVAL(outbuf,smb_com,SMBwritec); + SSVAL(outbuf,smb_vwv0,nwritten); + } + + END_PROFILE(SMBwriteBmpx); + return(outsize); +} + +/**************************************************************************** + Reply to a SMBwritebs (write block multiplex secondary) request. +****************************************************************************/ + +int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) +{ + size_t numtowrite; + ssize_t nwritten = -1; + int outsize = 0; + SMB_OFF_T startpos; + size_t tcount; + BOOL write_through; + int smb_doff; + char *data; + write_bmpx_struct *wbms; + BOOL send_response = False; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBwriteBs); + + CHECK_FSP(fsp,conn); + CHECK_WRITE(fsp); + + tcount = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); + numtowrite = SVAL(inbuf,smb_vwv6); + smb_doff = SVAL(inbuf,smb_vwv7); + + data = smb_base(inbuf) + smb_doff; + + /* We need to send an SMBwriteC response, not an SMBwritebs */ + SCVAL(outbuf,smb_com,SMBwritec); + + /* This fd should have an auxiliary struct attached, + check that it does */ + wbms = fsp->wbmpx_ptr; + if(!wbms) { + END_PROFILE(SMBwriteBs); + return(-1); + } + + /* If write through is set we can return errors, else we must cache them */ + write_through = wbms->wr_mode; + + /* Check for an earlier error */ + if(wbms->wr_discard) { + END_PROFILE(SMBwriteBs); + return -1; /* Just discard the packet */ + } + + nwritten = write_file(fsp,data,startpos,numtowrite); + + if(lp_syncalways(SNUM(conn)) || write_through) + sync_file(conn,fsp); + + if (nwritten < (ssize_t)numtowrite) { + if(write_through) { + /* We are returning an error - we can delete the aux struct */ + SAFE_FREE(wbms); + fsp->wbmpx_ptr = NULL; + END_PROFILE(SMBwriteBs); + return(ERROR_DOS(ERRHRD,ERRdiskfull)); + } + END_PROFILE(SMBwriteBs); + return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull)); + } + + /* Increment the total written, if this matches tcount + we can discard the auxiliary struct (hurrah !) and return a writeC */ + wbms->wr_total_written += nwritten; + if(wbms->wr_total_written >= tcount) { + if (write_through) { + outsize = set_message(outbuf,1,0,True); + SSVAL(outbuf,smb_vwv0,wbms->wr_total_written); + send_response = True; + } + + SAFE_FREE(wbms); + fsp->wbmpx_ptr = NULL; + } + + if(send_response) { + END_PROFILE(SMBwriteBs); + return(outsize); + } + + END_PROFILE(SMBwriteBs); + return(-1); +} + /**************************************************************************** - reply to a SMBgetattrE + Reply to a SMBgetattrE. ****************************************************************************/ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c index 03f307164d9..9a61a76f6fe 100644 --- a/source/smbd/sec_ctx.c +++ b/source/smbd/sec_ctx.c @@ -21,7 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern struct current_user current_user; struct sec_ctx { @@ -60,10 +59,8 @@ static BOOL become_uid(uid_t uid) /* Set effective user id */ set_effective_uid(uid); - current_user.uid = uid; DO_PROFILE_INC(uid_changes); - return True; } @@ -89,8 +86,6 @@ static BOOL become_gid(gid_t gid) /* Set effective group id */ set_effective_gid(gid); - current_user.gid = gid; - return True; } @@ -157,14 +152,14 @@ int get_current_groups(int *p_ngroups, gid_t **p_groups) } if ((ngroups = sys_getgroups(ngroups,groups)) == -1) { - safe_free(groups); + SAFE_FREE(groups); return -1; } (*p_ngroups) = ngroups; (*p_groups) = groups; - DEBUG( 3, ( "get_current_groups: uid %u is in %u groups: ", (unsigned int)getuid() , ngroups ) ); + DEBUG( 3, ( "get_current_groups: user is in %u groups: ", ngroups ) ); for (i = 0; i < ngroups; i++ ) { DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) ); } @@ -181,11 +176,10 @@ void delete_nt_token(NT_USER_TOKEN **pptoken) { if (*pptoken) { NT_USER_TOKEN *ptoken = *pptoken; - safe_free( ptoken->user_sids ); + SAFE_FREE( ptoken->user_sids ); ZERO_STRUCTP(ptoken); } - safe_free(*pptoken); - *pptoken = NULL; + SAFE_FREE(*pptoken); } /**************************************************************************** @@ -205,7 +199,7 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) ZERO_STRUCTP(token); if ((token->user_sids = (DOM_SID *)memdup( ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids )) == NULL) { - free(token); + SAFE_FREE(token); return NULL; } @@ -248,8 +242,7 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid) prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1]; - safe_free(prev_ctx_p->groups); - prev_ctx_p->groups = NULL; + SAFE_FREE(prev_ctx_p->groups); prev_ctx_p->ngroups = 0; get_current_groups(&prev_ctx_p->ngroups, &prev_ctx_p->groups); @@ -340,7 +333,7 @@ void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN ctx_p->ngroups = ngroups; - safe_free(ctx_p->groups); + SAFE_FREE(ctx_p->groups); if (token && (token == ctx_p->token)) smb_panic("DUPLICATE_TOKEN"); @@ -397,7 +390,7 @@ BOOL pop_sec_ctx(void) ctx_p->uid = (uid_t)-1; ctx_p->gid = (gid_t)-1; - safe_free(ctx_p->groups); + SAFE_FREE(ctx_p->groups); ctx_p->ngroups = 0; delete_nt_token(&ctx_p->token); diff --git a/source/smbd/server.c b/source/smbd/server.c index a8bccc548d9..b3b428a9b42 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -22,7 +22,6 @@ #include "includes.h" pstring servicesf = CONFIGFILE; -extern pstring debugf; extern fstring global_myworkgroup; extern pstring global_myname; @@ -34,8 +33,6 @@ int last_message = -1; /* a useful macro to debug the last message processed */ #define LAST_MESSAGE() smb_fn_name(last_message) -extern int DEBUGLEVEL; - extern pstring user_socket_options; #ifdef WITH_DFS @@ -104,7 +101,7 @@ static BOOL open_sockets_inetd(void) /**************************************************************************** open the socket communication ****************************************************************************/ -static BOOL open_sockets(BOOL is_daemon,int port) +static BOOL open_sockets(BOOL is_daemon,BOOL interactive, int port) { int num_interfaces = iface_count(); int fd_listenset[FD_SETSIZE]; @@ -212,14 +209,14 @@ max can be %d\n", memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set)); - num = sys_select(FD_SETSIZE,&lfds,NULL); + num = sys_select(FD_SETSIZE,&lfds,NULL,NULL,NULL); if (num == -1 && errno == EINTR) { extern VOLATILE sig_atomic_t reload_after_sighup; /* check for sighup processing */ if (reload_after_sighup) { - unbecome_user(); + change_to_root_user(); DEBUG(1,("Reloading services after SIGHUP\n")); reload_services(False); reload_after_sighup = False; @@ -258,7 +255,10 @@ max can be %d\n", strerror(errno))); continue; } - + + if (smbd_server_fd() != -1 && interactive) + return True; + if (smbd_server_fd() != -1 && sys_fork()==0) { /* Child code ... */ @@ -365,7 +365,7 @@ BOOL reload_services(BOOL test) reset_stat_cache(); /* this forces service parameters to be flushed */ - become_service(NULL,True); + set_current_service(NULL,True); return(ret); } @@ -398,7 +398,7 @@ static BOOL dump_core(void) { char *p; pstring dname; - pstrcpy(dname,debugf); + pstrcpy(dname,lp_logfile()); if ((p=strrchr(dname,'/'))) *p=0; pstrcat(dname,"/corefiles"); mkdir(dname,0700); @@ -434,11 +434,11 @@ update the current smbd process count static void decrement_smbd_process_count(void) { - int total_smbds; + int32 total_smbds; if (lp_max_smbd_processes()) { total_smbds = 0; - tdb_change_int_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1); + tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1); } } @@ -454,7 +454,7 @@ void exit_server(char *reason) if (!firsttime) exit(0); firsttime = 0; - unbecome_user(); + change_to_root_user(); DEBUG(2,("Closing connections\n")); conn_close_all(); @@ -462,9 +462,8 @@ void exit_server(char *reason) invalidate_all_vuids(); /* delete our entry in the connections database. */ - if (lp_status(-1)) { - yield_connection(NULL,"",MAXSTATUS); - } + if (lp_status(-1)) + yield_connection(NULL,""); respond_to_all_remaining_local_messages(); decrement_smbd_process_count(); @@ -532,10 +531,11 @@ usage on the program static void usage(char *pname) { - printf("Usage: %s [-DaoPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname); + printf("Usage: %s [-DaioPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname); printf(" [-O socket options] [-s services file]\n"); - printf("\t-D Become a daemon\n"); + printf("\t-D Become a daemon (default)\n"); printf("\t-a Append to log file (default)\n"); + printf("\t-i Run interactive (not a daemon)\n"); printf("\t-o Overwrite log file, don't append\n"); printf("\t-h Print usage\n"); printf("\t-? Print usage\n"); @@ -557,10 +557,12 @@ static void usage(char *pname) extern BOOL append_log; /* shall I run as a daemon */ BOOL is_daemon = False; + BOOL interactive = False; BOOL specified_logfile = False; int port = SMB_PORT; int opt; extern char *optarg; + pstring logfile; #ifdef HAVE_SET_AUTH_PARAMETERS set_auth_parameters(argc,argv); @@ -572,7 +574,7 @@ static void usage(char *pname) argc--; } - while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dp:h?Vaof:")) ) + while ( EOF != (opt = getopt(argc, argv, "O:l:s:d:Dip:h?Vaof:")) ) switch (opt) { case 'O': pstrcpy(user_socket_options,optarg); @@ -584,7 +586,8 @@ static void usage(char *pname) case 'l': specified_logfile = True; - slprintf(debugf, sizeof(debugf)-1, "%s/log.smbd", optarg); + slprintf(logfile, sizeof(logfile)-1, "%s/log.smbd", optarg); + lp_set_logfile(logfile); break; case 'a': @@ -599,6 +602,10 @@ static void usage(char *pname) is_daemon = True; break; + case 'i': + interactive = True; + break; + case 'd': if (*optarg == 'A') DEBUGLEVEL = 10000; @@ -638,12 +645,13 @@ static void usage(char *pname) TimeInit(); if(!specified_logfile) { - slprintf(debugf, sizeof(debugf)-1, "%s/log.smbd", LOGFILEBASE); + slprintf(logfile, sizeof(logfile)-1, "%s/log.smbd", LOGFILEBASE); + lp_set_logfile(logfile); } pstrcpy(remote_machine, "smbd"); - setup_logging(argv[0],False); + setup_logging(argv[0],interactive); charset_initialise(); @@ -683,11 +691,12 @@ static void usage(char *pname) umask(0); init_sec_ctx(); + init_conn_ctx(); reopen_logs(); - DEBUG(1,( "smbd version %s started.\n", VERSION)); - DEBUGADD(1,( "Copyright Andrew Tridgell 1992-1998\n")); + DEBUG(0,( "smbd version %s started.\n", VERSION)); + DEBUGADD(0,( "Copyright Andrew Tridgell and the Samba Team 1992-2002\n")); DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid())); @@ -731,59 +740,66 @@ static void usage(char *pname) DEBUG(3,( "loaded services\n")); if (!is_daemon && !is_a_socket(0)) { - DEBUG(0,("standard input is not a socket, assuming -D option\n")); + if (!interactive) + DEBUG(0,("standard input is not a socket, assuming -D option\n")); + + /* + * Setting is_daemon here prevents us from eventually calling + * the open_sockets_inetd() + */ + is_daemon = True; } - if (is_daemon) { + if (is_daemon && !interactive) { DEBUG( 3, ( "Becoming a daemon.\n" ) ); become_daemon(); } - if (!directory_exist(lp_lockdir(), NULL)) { +#if HAVE_SETPGID + /* + * If we're interactive we want to set our own process group for + * signal management. + */ + if (interactive) + setpgid( (pid_t)0, (pid_t)0); +#endif + + if (!directory_exist(lp_lockdir(), NULL)) mkdir(lp_lockdir(), 0755); - } - if (is_daemon) { + if (is_daemon) pidfile_create("smbd"); - } - if (!message_init()) { + if (!message_init()) exit(1); - } /* Setup the main smbd so that we can get messages. */ - if (lp_status(-1)) { - claim_connection(NULL,"",MAXSTATUS,True); - } + if (lp_status(-1)) + claim_connection(NULL,"",0,True); /* Attempt to migrate from an old 2.0.x machine account file. */ - if (!migrate_from_old_password_file(global_myworkgroup)) { + if (!migrate_from_old_password_file(global_myworkgroup)) DEBUG(0,("Failed to migrate from old MAC file.\n")); - } - if (!open_sockets(is_daemon,port)) + if (!open_sockets(is_daemon,interactive,port)) exit(1); /* - * everything after this point is run after the fork() + * Everything after this point is run after the fork(). */ - if (!locking_init(0)) { + if (!locking_init(0)) exit(1); - } - if (!print_backend_init()) { + if (!print_backend_init()) exit(1); - } - if (!share_info_db_init()) { + if (!share_info_db_init()) exit(1); - } - if(!initialize_password_db(False)) { + if(!initialize_password_db(False)) exit(1); - } /* possibly reload the services file. */ reload_services(True); @@ -799,14 +815,12 @@ static void usage(char *pname) } /* Setup oplocks */ - if (!init_oplocks()) { + if (!init_oplocks()) exit(1); - } /* Setup change notify */ - if (!init_change_notify()) { + if (!init_change_notify()) exit(1); - } smbd_process(); diff --git a/source/smbd/service.c b/source/smbd/service.c index ffbdefbecb7..515bcc5c792 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - extern struct timeval smb_last_time; extern int case_default; extern BOOL case_preserve; @@ -36,9 +34,10 @@ extern fstring remote_machine; /**************************************************************************** -load parameters specific to a connection/service + Load parameters specific to a connection/service. ****************************************************************************/ -BOOL become_service(connection_struct *conn,BOOL do_chdir) + +BOOL set_current_service(connection_struct *conn,BOOL do_chdir) { extern char magic_char; static connection_struct *last_conn; @@ -126,7 +125,7 @@ int find_service(char *service) /* now handle the special case of a home directory */ if (iService < 0) { - char *phome_dir = get_user_home_dir(service); + char *phome_dir = get_user_service_home_dir(service); if(!phome_dir) { @@ -135,7 +134,7 @@ int find_service(char *service) * be a Windows to unix mapped user name. */ if(map_username(service)) - phome_dir = get_user_home_dir(service); + phome_dir = get_user_service_home_dir(service); } DEBUG(3,("checking for home directory %s gave %s\n",service, @@ -214,8 +213,11 @@ int find_service(char *service) /**************************************************************************** - make a connection to a service + Make a connection to a service. This function is designed to be called + AS ROOT and will return to being root on exit ! Modified current_user conn + and vuid elements. ****************************************************************************/ + connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode) { int snum; @@ -223,8 +225,16 @@ connection_struct *make_connection(char *service,char *user,char *password, int BOOL guest = False; BOOL force = False; connection_struct *conn; + uid_t euid; int ret; + /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */ + + if (!non_root_mode() && ((euid = geteuid()) != 0)) { + DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid )); + smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); + } + strlower(service); snum = find_service(service); @@ -320,6 +330,8 @@ connection_struct *make_connection(char *service,char *user,char *password, int return NULL; } + add_session_user(user); + conn = conn_new(); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); @@ -339,7 +351,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int conn->read_only = lp_readonly(snum); - { pstring list; StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1); @@ -482,7 +493,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int conn->groups = NULL; /* Find all the groups this uid is in and - store them. Used by become_user() */ + store them. Used by change_to_user() */ initialise_groups(conn->user, conn->uid, conn->gid); get_current_groups(&conn->ngroups,&conn->groups); @@ -499,7 +510,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int conn->nt_user_token = create_nt_token(conn->uid, conn->gid, conn->ngroups, conn->groups, - guest); + guest, NULL); /* * New code to check if there's a share security descripter @@ -516,7 +527,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int *ecode = ERRaccess; DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n", service )); - yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); + yield_connection(conn, lp_servicename(SNUM(conn))); conn_free(conn); return NULL; } else { @@ -528,7 +539,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int if (!vfs_init(conn)) { DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn)))); - yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); + yield_connection(conn, lp_servicename(SNUM(conn))); conn_free(conn); return NULL; } @@ -542,31 +553,42 @@ connection_struct *make_connection(char *service,char *user,char *password, int ret = smbrun(cmd,NULL); if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); - yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); + yield_connection(conn, lp_servicename(SNUM(conn))); conn_free(conn); *ecode = ERRsrverror; return NULL; } } - if (!become_user(conn, conn->vuid)) { + if (!change_to_user(conn, conn->vuid)) { DEBUG(0,("Can't become connected user!\n")); - yield_connection(conn, - lp_servicename(SNUM(conn)), - lp_max_connections(SNUM(conn))); + yield_connection(conn, lp_servicename(SNUM(conn))); conn_free(conn); *ecode = ERRbadpw; return NULL; } + /* execute any "preexec = " line */ + if (*lp_preexec(SNUM(conn))) { + pstring cmd; + pstrcpy(cmd,lp_preexec(SNUM(conn))); + standard_sub_conn(conn,cmd); + ret = smbrun(cmd,NULL); + if (ret != 0 && lp_preexec_close(SNUM(conn))) { + DEBUG(1,("preexec gave %d - failing connection\n", ret)); + yield_connection(conn, lp_servicename(SNUM(conn))); + conn_free(conn); + *ecode = ERRsrverror; + return NULL; + } + } + if (vfs_ChDir(conn,conn->connectpath) != 0) { DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n", remote_machine, conn->client_address, conn->connectpath,strerror(errno))); - unbecome_user(); - yield_connection(conn, - lp_servicename(SNUM(conn)), - lp_max_connections(SNUM(conn))); + change_to_root_user(); + yield_connection(conn, lp_servicename(SNUM(conn))); conn_free(conn); *ecode = ERRnosuchshare; return NULL; @@ -585,23 +607,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int } #endif - add_session_user(user); - - /* execute any "preexec = " line */ - if (*lp_preexec(SNUM(conn))) { - pstring cmd; - pstrcpy(cmd,lp_preexec(SNUM(conn))); - standard_sub_conn(conn,cmd); - ret = smbrun(cmd,NULL); - if (ret != 0 && lp_preexec_close(SNUM(conn))) { - DEBUG(1,("preexec gave %d - failing connection\n", ret)); - yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); - conn_free(conn); - *ecode = ERRsrverror; - return NULL; - } - } - /* * Print out the 'connected as' stuff here as we need * to know the effective uid and gid we will be using. @@ -616,7 +621,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int } /* we've finished with the sensitive stuff */ - unbecome_user(); + change_to_root_user(); /* Add veto/hide lists */ if (!IS_IPC(conn) && !IS_PRINT(conn)) { @@ -635,15 +640,15 @@ connection_struct *make_connection(char *service,char *user,char *password, int return(conn); } - /**************************************************************************** -close a cnum + Close a cnum ****************************************************************************/ + void close_cnum(connection_struct *conn, uint16 vuid) { DirCacheFlush(SNUM(conn)); - unbecome_user(); + change_to_root_user(); DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n", remote_machine,conn->client_address, @@ -657,24 +662,21 @@ void close_cnum(connection_struct *conn, uint16 vuid) } - yield_connection(conn, - lp_servicename(SNUM(conn)), - lp_max_connections(SNUM(conn))); + yield_connection(conn, lp_servicename(SNUM(conn))); file_close_conn(conn); dptr_closecnum(conn); /* execute any "postexec = " line */ if (*lp_postexec(SNUM(conn)) && - become_user(conn, vuid)) { + change_to_user(conn, vuid)) { pstring cmd; pstrcpy(cmd,lp_postexec(SNUM(conn))); standard_sub_conn(conn,cmd); smbrun(cmd,NULL); - unbecome_user(); } - unbecome_user(); + change_to_root_user(); /* execute any "root postexec = " line */ if (*lp_rootpostexec(SNUM(conn))) { pstring cmd; diff --git a/source/smbd/session.c b/source/smbd/session.c index bf21677f566..7f057256cac 100644 --- a/source/smbd/session.c +++ b/source/smbd/session.c @@ -89,9 +89,12 @@ BOOL session_claim(uint16 vuid) return False; } - hostname = client_name(); - if (strequal(hostname,"UNKNOWN")) - hostname = client_addr(); + /* Don't resolve the hostname in smbd as we can pause for a long + time while waiting for DNS timeouts to occur. The correct + place to do this is in the code that displays the session + information. */ + + hostname = client_addr(); fstrcpy(sessionid.username, vuser->user.unix_name); fstrcpy(sessionid.hostname, hostname); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 89515f6351e..bfa304605f6 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -2,9 +2,8 @@ Unix SMB/Netbios implementation. Version 1.9. SMB transaction2 handling - Copyright (C) Jeremy Allison 1994-1998 - Extensively modified by Andrew Tridgell, 1995 + Copyright (C) Jeremy Allison 1994-2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +22,6 @@ #include "includes.h" -extern int DEBUGLEVEL; extern int Protocol; extern BOOL case_sensitive; extern int smb_read_error; @@ -38,275 +36,390 @@ extern pstring global_myname; set correctly for the type of call. HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -static int send_trans2_replies(char *outbuf, int bufsize, char *params, - int paramsize, char *pdata, int datasize) + +static int send_trans2_replies(char *outbuf, int bufsize, char *params, int paramsize, char *pdata, int datasize) { - /* As we are using a protocol > LANMAN1 then the max_send - variable must have been set in the sessetupX call. - This takes precedence over the max_xmit field in the - global struct. These different max_xmit variables should - be merged as this is now too confusing */ - - extern int max_send; - int data_to_send = datasize; - int params_to_send = paramsize; - int useable_space; - char *pp = params; - char *pd = pdata; - int params_sent_thistime, data_sent_thistime, total_sent_thistime; - int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ - int data_alignment_offset = 0; - - /* Initially set the wcnt area to be 10 - this is true for all - trans2 replies */ - set_message(outbuf,10,0,True); - - /* If there genuinely are no parameters or data to send just send - the empty packet */ - if(params_to_send == 0 && data_to_send == 0) - { - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_trans2_replies: send_smb failed.\n"); - return 0; - } - - /* When sending params and data ensure that both are nicely aligned */ - /* Only do this alignment when there is also data to send - else - can cause NT redirector problems. */ - if (((params_to_send % 4) != 0) && (data_to_send != 0)) - data_alignment_offset = 4 - (params_to_send % 4); - - /* Space is bufsize minus Netbios over TCP header minus SMB header */ - /* The alignment_offset is to align the param bytes on an even byte - boundary. NT 4.0 Beta needs this to work correctly. */ - useable_space = bufsize - ((smb_buf(outbuf)+ - alignment_offset+data_alignment_offset) - - outbuf); - - /* useable_space can never be more than max_send minus the - alignment offset. */ - useable_space = MIN(useable_space, - max_send - (alignment_offset+data_alignment_offset)); - - - while (params_to_send || data_to_send) - { - /* Calculate whether we will totally or partially fill this packet */ - total_sent_thistime = params_to_send + data_to_send + - alignment_offset + data_alignment_offset; - /* We can never send more than useable_space */ - /* - * Note that 'useable_space' does not include the alignment offsets, - * but we must include the alignment offsets in the calculation of - * the length of the data we send over the wire, as the alignment offsets - * are sent here. Fix from Marc_Jacobsen@hp.com. - */ - total_sent_thistime = MIN(total_sent_thistime, useable_space+ - alignment_offset + data_alignment_offset); - - set_message(outbuf, 10, total_sent_thistime, True); - - /* Set total params and data to be sent */ - SSVAL(outbuf,smb_tprcnt,paramsize); - SSVAL(outbuf,smb_tdrcnt,datasize); - - /* Calculate how many parameters and data we can fit into - this packet. Parameters get precedence */ - - params_sent_thistime = MIN(params_to_send,useable_space); - data_sent_thistime = useable_space - params_sent_thistime; - data_sent_thistime = MIN(data_sent_thistime,data_to_send); - - SSVAL(outbuf,smb_prcnt, params_sent_thistime); - - /* smb_proff is the offset from the start of the SMB header to the - parameter bytes, however the first 4 bytes of outbuf are - the Netbios over TCP header. Thus use smb_base() to subtract - them from the calculation */ - - SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - - if(params_sent_thistime == 0) - SSVAL(outbuf,smb_prdisp,0); - else - /* Absolute displacement of param bytes sent in this packet */ - SSVAL(outbuf,smb_prdisp,pp - params); - - SSVAL(outbuf,smb_drcnt, data_sent_thistime); - if(data_sent_thistime == 0) - { - SSVAL(outbuf,smb_droff,0); - SSVAL(outbuf,smb_drdisp, 0); - } - else - { - /* The offset of the data bytes is the offset of the - parameter bytes plus the number of parameters being sent this time */ - SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); - SSVAL(outbuf,smb_drdisp, pd - pdata); - } - - /* Copy the param bytes into the packet */ - if(params_sent_thistime) - memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); - /* Copy in the data bytes */ - if(data_sent_thistime) - memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ - data_alignment_offset,pd,data_sent_thistime); - - DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", - params_to_send, data_to_send, paramsize, datasize)); - - /* Send the packet */ - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_trans2_replies: send_smb failed.\n"); - - pp += params_sent_thistime; - pd += data_sent_thistime; - - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; - - /* Sanity check */ - if(params_to_send < 0 || data_to_send < 0) - { - DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } - - return 0; -} + /* As we are using a protocol > LANMAN1 then the max_send + variable must have been set in the sessetupX call. + This takes precedence over the max_xmit field in the + global struct. These different max_xmit variables should + be merged as this is now too confusing */ + + extern int max_send; + int data_to_send = datasize; + int params_to_send = paramsize; + int useable_space; + char *pp = params; + char *pd = pdata; + int params_sent_thistime, data_sent_thistime, total_sent_thistime; + int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ + int data_alignment_offset = 0; + + /* Initially set the wcnt area to be 10 - this is true for all + trans2 replies */ + set_message(outbuf,10,0,True); + + /* If there genuinely are no parameters or data to send just send + the empty packet */ + + if(params_to_send == 0 && data_to_send == 0) { + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_trans2_replies: send_smb failed."); + return 0; + } + + /* When sending params and data ensure that both are nicely aligned */ + /* Only do this alignment when there is also data to send - else + can cause NT redirector problems. */ + + if (((params_to_send % 4) != 0) && (data_to_send != 0)) + data_alignment_offset = 4 - (params_to_send % 4); + + /* Space is bufsize minus Netbios over TCP header minus SMB header */ + /* The alignment_offset is to align the param bytes on an even byte + boundary. NT 4.0 Beta needs this to work correctly. */ + + useable_space = bufsize - ((smb_buf(outbuf)+ alignment_offset+data_alignment_offset) - outbuf); + + /* useable_space can never be more than max_send minus the alignment offset. */ + + useable_space = MIN(useable_space, max_send - (alignment_offset+data_alignment_offset)); + + + while (params_to_send || data_to_send) { + /* Calculate whether we will totally or partially fill this packet */ + + total_sent_thistime = params_to_send + data_to_send + alignment_offset + data_alignment_offset; + + /* We can never send more than useable_space */ + /* + * Note that 'useable_space' does not include the alignment offsets, + * but we must include the alignment offsets in the calculation of + * the length of the data we send over the wire, as the alignment offsets + * are sent here. Fix from Marc_Jacobsen@hp.com. + */ + + total_sent_thistime = MIN(total_sent_thistime, useable_space+ alignment_offset + data_alignment_offset); + + set_message(outbuf, 10, total_sent_thistime, True); + + /* Set total params and data to be sent */ + SSVAL(outbuf,smb_tprcnt,paramsize); + SSVAL(outbuf,smb_tdrcnt,datasize); + + /* Calculate how many parameters and data we can fit into + this packet. Parameters get precedence */ + + params_sent_thistime = MIN(params_to_send,useable_space); + data_sent_thistime = useable_space - params_sent_thistime; + data_sent_thistime = MIN(data_sent_thistime,data_to_send); + + SSVAL(outbuf,smb_prcnt, params_sent_thistime); + + /* smb_proff is the offset from the start of the SMB header to the + parameter bytes, however the first 4 bytes of outbuf are + the Netbios over TCP header. Thus use smb_base() to subtract + them from the calculation */ + SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); + + if(params_sent_thistime == 0) + SSVAL(outbuf,smb_prdisp,0); + else + /* Absolute displacement of param bytes sent in this packet */ + SSVAL(outbuf,smb_prdisp,pp - params); + + SSVAL(outbuf,smb_drcnt, data_sent_thistime); + if(data_sent_thistime == 0) { + SSVAL(outbuf,smb_droff,0); + SSVAL(outbuf,smb_drdisp, 0); + } else { + /* The offset of the data bytes is the offset of the + parameter bytes plus the number of parameters being sent this time */ + SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - + smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); + SSVAL(outbuf,smb_drdisp, pd - pdata); + } + + /* Copy the param bytes into the packet */ + + if(params_sent_thistime) + memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + + /* Copy in the data bytes */ + + if(data_sent_thistime) + memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ + data_alignment_offset,pd,data_sent_thistime); + + DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", + params_sent_thistime, data_sent_thistime, useable_space)); + DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", + params_to_send, data_to_send, paramsize, datasize)); + + /* Send the packet */ + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_trans2_replies: send_smb failed."); + + pp += params_sent_thistime; + pd += data_sent_thistime; + + params_to_send -= params_sent_thistime; + data_to_send -= data_sent_thistime; + + /* Sanity check */ + + if(params_to_send < 0 || data_to_send < 0) { + DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", + params_to_send, data_to_send)); + return -1; + } + } + + return 0; +} /**************************************************************************** - reply to a TRANSACT2_OPEN + Reply to a TRANSACT2_OPEN. ****************************************************************************/ -static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, - int bufsize, - char **pparams, char **ppdata) + +static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; - int16 open_mode = SVAL(params, 2); - int16 open_attr = SVAL(params,6); - BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); + char *params = *pparams; + int16 open_mode; + int16 open_attr; + BOOL oplock_request; #if 0 - BOOL return_additional_info = BITSETW(params,0); - int16 open_sattr = SVAL(params, 4); - time_t open_time = make_unix_date3(params+8); + BOOL return_additional_info; + int16 open_sattr; + time_t open_time; #endif - int16 open_ofun = SVAL(params,12); - int32 open_size = IVAL(params,14); - char *pname = ¶ms[28]; - int16 namelen = strlen(pname)+1; + int16 open_ofun; + int32 open_size; + char *pname; + int16 namelen; - pstring fname; - mode_t unixmode; - SMB_OFF_T size=0; - int fmode=0,mtime=0,rmode; - SMB_INO_T inode = 0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp; + pstring fname; + mode_t unixmode; + SMB_OFF_T size=0; + int fmode=0,mtime=0,rmode; + SMB_INO_T inode = 0; + SMB_STRUCT_STAT sbuf; + int smb_action = 0; + BOOL bad_path = False; + files_struct *fsp; + + /* + * Ensure we have enough parameters to perform the operation. + */ + + if (total_params < 29) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + open_mode = SVAL(params, 2); + open_attr = SVAL(params,6); + oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); +#if 0 + return_additional_info = BITSETW(params,0); + open_sattr = SVAL(params, 4); + open_time = make_unix_date3(params+8); +#endif + open_ofun = SVAL(params,12); + open_size = IVAL(params,14); + pname = ¶ms[28]; + namelen = strlen(pname)+1; - StrnCpy(fname,pname,namelen); + StrnCpy(fname,pname,namelen); - DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", - fname,open_mode, open_attr, open_ofun, open_size)); + DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", + fname,open_mode, open_attr, open_ofun, open_size)); - if (IS_IPC(conn)) { - return(ERROR(ERRSRV,ERRaccess)); - } + if (IS_IPC(conn)) + return(ERROR_DOS(ERRSRV,ERRaccess)); - /* XXXX we need to handle passed times, sattr and flags */ + /* XXXX we need to handle passed times, sattr and flags */ - unix_convert(fname,conn,0,&bad_path,&sbuf); + unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - unixmode = unix_mode(conn,open_attr | aARCH, fname); + if (!check_name(fname,conn)) { + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + unixmode = unix_mode(conn,open_attr | aARCH, fname); - fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode, - oplock_request, &rmode,&smb_action); + fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode, + oplock_request, &rmode,&smb_action); - if (!fsp) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - mtime = sbuf.st_mtime; - inode = sbuf.st_ino; - if (fmode & aDIR) { - close_file(fsp,False); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - /* Realloc the size of parameters and data we will return */ - params = Realloc(*pparams, 28); - if( params == NULL ) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; - - memset((char *)params,'\0',28); - SSVAL(params,0,fsp->fnum); - SSVAL(params,2,fmode); - put_dos_date2(params,4, mtime); - SIVAL(params,8, (uint32)size); - SSVAL(params,12,rmode); - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - smb_action |= EXTENDED_OPLOCK_GRANTED; - } - - SSVAL(params,18,smb_action); - /* - * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes. - */ - SIVAL(params,20,inode); + if (!fsp) { + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + size = sbuf.st_size; + fmode = dos_mode(conn,fname,&sbuf); + mtime = sbuf.st_mtime; + inode = sbuf.st_ino; + if (fmode & aDIR) { + close_file(fsp,False); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + } + + /* Realloc the size of parameters and data we will return */ + params = Realloc(*pparams, 28); + if( params == NULL ) + return(ERROR_DOS(ERRDOS,ERRnomem)); + *pparams = params; + + memset((char *)params,'\0',28); + SSVAL(params,0,fsp->fnum); + SSVAL(params,2,fmode); + put_dos_date2(params,4, mtime); + SIVAL(params,8, (uint32)size); + SSVAL(params,12,rmode); + + if (oplock_request && lp_fake_oplocks(SNUM(conn))) + smb_action |= EXTENDED_OPLOCK_GRANTED; + + SSVAL(params,18,smb_action); + + /* + * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes. + */ + SIVAL(params,20,inode); - /* Send the required number of replies */ - send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); + /* Send the required number of replies */ + send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); - return -1; + return -1; } /********************************************************* -* Routine to check if a given string matches exactly. -* as a special case a mask of "." does NOT match. That -* is required for correct wildcard semantics -* Case can be significant or not. + Routine to check if a given string matches exactly. + as a special case a mask of "." does NOT match. That + is required for correct wildcard semantics + Case can be significant or not. **********************************************************/ + static BOOL exact_match(char *str,char *mask, BOOL case_sig) { - if (mask[0] == '.' && mask[1] == 0) return False; - if (case_sig) return strcmp(str,mask)==0; + if (mask[0] == '.' && mask[1] == 0) + return False; + if (case_sig) + return strcmp(str,mask)==0; return strcasecmp(str,mask) == 0; } /**************************************************************************** - get a level dependent lanman2 dir entry. + Return the filetype for UNIX extensions. ****************************************************************************/ + +static uint32 unix_filetype(mode_t mode) +{ + if(S_ISREG(mode)) + return UNIX_TYPE_FILE; + else if(S_ISDIR(mode)) + return UNIX_TYPE_DIR; +#ifdef S_ISLNK + else if(S_ISLNK(mode)) + return UNIX_TYPE_SYMLINK; +#endif +#ifdef S_ISCHR + else if(S_ISCHR(mode)) + return UNIX_TYPE_CHARDEV; +#endif +#ifdef S_ISBLK + else if(S_ISBLK(mode)) + return UNIX_TYPE_BLKDEV; +#endif +#ifdef S_ISFIFO + else if(S_ISFIFO(mode)) + return UNIX_TYPE_FIFO; +#endif +#ifdef S_ISSOCK + else if(S_ISSOCK(mode)) + return UNIX_TYPE_SOCKET; +#endif + + DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode)); + return UNIX_TYPE_UNKNOWN; +} + +/**************************************************************************** + Return the major devicenumber for UNIX extensions. +****************************************************************************/ + +static uint32 unix_dev_major(SMB_DEV_T dev) +{ +#if defined(HAVE_DEVICE_MAJOR_FN) + return (uint32)major(dev); +#else + return (uint32)(dev >> 8); +#endif +} + +/**************************************************************************** + Return the minor devicenumber for UNIX extensions. +****************************************************************************/ + +static uint32 unix_dev_minor(SMB_DEV_T dev) +{ +#if defined(HAVE_DEVICE_MINOR_FN) + return (uint32)minor(dev); +#else + return (uint32)(dev & 0xff); +#endif +} + +/**************************************************************************** + Map wire perms onto standard UNIX permissions. Obey share restrictions. +****************************************************************************/ + +static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *pst, uint32 perms) +{ + mode_t ret = 0; + + if (perms == SMB_MODE_NO_CHANGE) + return pst->st_mode; + + ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0); + ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0); + ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0); + ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0); + ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0); + ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0); + ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0); + ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0); + ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0); +#ifdef S_ISVTX + ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0); +#endif +#ifdef S_ISGID + ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0); +#endif +#ifdef S_ISUID + ret |= ((perms & UNIX_SET_UID ) ? S_ISVTX : 0); +#endif + + if (VALID_STAT(*pst) && S_ISDIR(pst->st_mode)) { + ret &= lp_dir_mask(SNUM(conn)); + /* Add in force bits */ + ret |= lp_force_dir_mode(SNUM(conn)); + } else { + /* Apply mode mask */ + ret &= lp_create_mask(SNUM(conn)); + /* Add in force bits */ + ret |= lp_force_create_mode(SNUM(conn)); + } + + return ret; +} + +/**************************************************************************** + Get a level dependent lanman2 dir entry. +****************************************************************************/ + static BOOL get_lanman2_dir_entry(connection_struct *conn, char *path_mask,int dirtype,int info_level, int requires_resume_key, @@ -315,975 +428,1093 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, BOOL *out_of_space, BOOL *got_exact_match, int *last_name_off) { - char *dname; - BOOL found = False; - SMB_STRUCT_STAT sbuf; - pstring mask; - pstring pathreal; - pstring fname; - char *p, *pdata = *ppdata; - uint32 reskey=0; - int prev_dirpos=0; - int mode=0; - SMB_OFF_T size = 0; - uint32 len; - time_t mdate=0, adate=0, cdate=0; - char *nameptr; - BOOL was_8_3; - int nt_extmode; /* Used for NT connections instead of mode */ - BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); - - *fname = 0; - *out_of_space = False; - *got_exact_match = False; - - if (!conn->dirptr) - return(False); - - p = strrchr(path_mask,'/'); - if(p != NULL) - { - if(p[1] == '\0') - pstrcpy(mask,"*.*"); - else - pstrcpy(mask, p+1); - } - else - pstrcpy(mask, path_mask); - - while (!found) - { - BOOL got_match; - - /* Needed if we run out of space */ - prev_dirpos = TellDir(conn->dirptr); - dname = ReadDirName(conn->dirptr); - - /* - * Due to bugs in NT client redirectors we are not using - * resume keys any more - set them to zero. - * Check out the related comments in findfirst/findnext. - * JRA. - */ - - reskey = 0; - - DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n", - (long)conn->dirptr,TellDir(conn->dirptr))); + char *dname; + BOOL found = False; + SMB_STRUCT_STAT sbuf; + pstring mask; + pstring pathreal; + pstring fname; + char *p, *pdata = *ppdata; + uint32 reskey=0; + int prev_dirpos=0; + int mode=0; + SMB_OFF_T size = 0; + SMB_OFF_T allocation_size = 0; + uint32 len; + time_t mdate=0, adate=0, cdate=0; + char *nameptr; + BOOL was_8_3; + int nt_extmode; /* Used for NT connections instead of mode */ + BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); + + *fname = 0; + *out_of_space = False; + *got_exact_match = False; + + if (!conn->dirptr) + return(False); + + p = strrchr(path_mask,'/'); + if(p != NULL) { + if(p[1] == '\0') + pstrcpy(mask,"*.*"); + else + pstrcpy(mask, p+1); + } else + pstrcpy(mask, path_mask); + + while (!found) { + BOOL got_match; + + /* Needed if we run out of space */ + prev_dirpos = TellDir(conn->dirptr); + dname = ReadDirName(conn->dirptr); + + /* + * Due to bugs in NT client redirectors we are not using + * resume keys any more - set them to zero. + * Check out the related comments in findfirst/findnext. + * JRA. + */ + + reskey = 0; + + DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n", + (long)conn->dirptr,TellDir(conn->dirptr))); - if (!dname) - return(False); - - pstrcpy(fname,dname); - - if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive))) { - got_match = mask_match(fname, mask, case_sensitive); - } - - if(!got_match && !is_8_3(fname, False)) { - - /* - * It turns out that NT matches wildcards against - * both long *and* short names. This may explain some - * of the wildcard wierdness from old DOS clients - * that some people have been seeing.... JRA. - */ - - pstring newname; - pstrcpy( newname, fname); - name_map_mangle( newname, True, False, SNUM(conn)); - if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive))) - got_match = mask_match(newname, mask, case_sensitive); - } - - if(got_match) - { - BOOL isdots = (strequal(fname,"..") || strequal(fname,".")); - if (dont_descend && !isdots) - continue; + if (!dname) + return(False); + + pstrcpy(fname,dname); + + if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive))) + got_match = mask_match(fname, mask, case_sensitive); + + if(!got_match && !is_8_3(fname, False)) { + + /* + * It turns out that NT matches wildcards against + * both long *and* short names. This may explain some + * of the wildcard wierdness from old DOS clients + * that some people have been seeing.... JRA. + */ + + pstring newname; + pstrcpy( newname, fname); + name_map_mangle( newname, True, False, SNUM(conn)); + if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive))) + got_match = mask_match(newname, mask, case_sensitive); + } + + if(got_match) { + BOOL isdots = (strequal(fname,"..") || strequal(fname,".")); + if (dont_descend && !isdots) + continue; - pstrcpy(pathreal,conn->dirpath); - if(needslash) - pstrcat(pathreal,"/"); - pstrcat(pathreal,dname); - if (vfs_stat(conn,pathreal,&sbuf) != 0) - { - /* Needed to show the msdfs symlinks as directories */ - if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn)) - || !is_msdfs_link(conn, pathreal, NULL, NULL)) - { - DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", - pathreal,strerror(errno))); - continue; - } - else - { - DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal)); - sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; - } - } - - mode = dos_mode(conn,pathreal,&sbuf); - - if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) { - DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype)); - continue; - } - - size = sbuf.st_size; - mdate = sbuf.st_mtime; - adate = sbuf.st_atime; - cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); - - if (lp_dos_filetime_resolution(SNUM(conn))) { - cdate &= ~1; - mdate &= ~1; - adate &= ~1; - } - - if(mode & aDIR) - size = 0; - - DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname)); + pstrcpy(pathreal,conn->dirpath); + if(needslash) + pstrcat(pathreal,"/"); + pstrcat(pathreal,dname); + + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (vfs_lstat(conn,pathreal,&sbuf) != 0) { + DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", + pathreal,strerror(errno))); + continue; + } + } else if (vfs_stat(conn,pathreal,&sbuf) != 0) { + /* Needed to show the msdfs symlinks as directories */ + if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn)) + || !is_msdfs_link(conn, pathreal, NULL, NULL)) { + DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", + pathreal,strerror(errno))); + continue; + } else { + DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal)); + sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; + } + } + + mode = dos_mode(conn,pathreal,&sbuf); + + if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) { + DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype)); + continue; + } + + size = sbuf.st_size; + allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size); + mdate = sbuf.st_mtime; + adate = sbuf.st_atime; + cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + + if (lp_dos_filetime_resolution(SNUM(conn))) { + cdate &= ~1; + mdate &= ~1; + adate &= ~1; + } + + if(mode & aDIR) + size = 0; + + DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname)); - found = True; - } - } - - name_map_mangle(fname,False,True,SNUM(conn)); - - p = pdata; - nameptr = p; - - nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL; - - switch (info_level) - { - case 1: - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - put_dos_date2(p,l1_fdateCreation,cdate); - put_dos_date2(p,l1_fdateLastAccess,adate); - put_dos_date2(p,l1_fdateLastWrite,mdate); - SIVAL(p,l1_cbFile,(uint32)size); - SIVAL(p,l1_cbFileAlloc,SMB_ROUNDUP(size,1024)); - SSVAL(p,l1_attrFile,mode); - SCVAL(p,l1_cchName,strlen(fname)); - pstrcpy(p + l1_achName, fname); - nameptr = p + l1_achName; - p += l1_achName + strlen(fname) + 1; - break; - - case 2: - /* info_level 2 */ - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - put_dos_date2(p,l2_fdateCreation,cdate); - put_dos_date2(p,l2_fdateLastAccess,adate); - put_dos_date2(p,l2_fdateLastWrite,mdate); - SIVAL(p,l2_cbFile,(uint32)size); - SIVAL(p,l2_cbFileAlloc,SMB_ROUNDUP(size,1024)); - SSVAL(p,l2_attrFile,mode); - SIVAL(p,l2_cbList,0); /* No extended attributes */ - SCVAL(p,l2_cchName,strlen(fname)); - pstrcpy(p + l2_achName, fname); - nameptr = p + l2_achName; - p += l2_achName + strlen(fname) + 1; - break; - - case 3: - SIVAL(p,0,reskey); - put_dos_date2(p,4,cdate); - put_dos_date2(p,8,adate); - put_dos_date2(p,12,mdate); - SIVAL(p,16,(uint32)size); - SIVAL(p,20,SMB_ROUNDUP(size,1024)); - SSVAL(p,24,mode); - SIVAL(p,26,4); - CVAL(p,30) = strlen(fname); - pstrcpy(p+31, fname); - nameptr = p+31; - p += 31 + strlen(fname) + 1; - break; - - case 4: - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - SIVAL(p,0,33+strlen(fname)+1); - put_dos_date2(p,4,cdate); - put_dos_date2(p,8,adate); - put_dos_date2(p,12,mdate); - SIVAL(p,16,(uint32)size); - SIVAL(p,20,SMB_ROUNDUP(size,1024)); - SSVAL(p,24,mode); - CVAL(p,32) = strlen(fname); - pstrcpy(p + 33, fname); - nameptr = p+33; - p += 33 + strlen(fname) + 1; - break; - - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - was_8_3 = is_8_3(fname, True); - len = 94+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date(p,cdate); p += 8; - put_long_date(p,adate); p += 8; - put_long_date(p,mdate); p += 8; - put_long_date(p,mdate); p += 8; - SOFF_T(p,0,size); - SOFF_T(p,8,size); - p += 16; - SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - SIVAL(p,0,0); p += 4; - if (!was_8_3) { - fstrcpy(p+2,fname); - if(!name_map_mangle(p+2,True,True,SNUM(conn))) - (p+2)[12] = 0; - strupper(p+2); - SSVAL(p, 0, strlen(p+2)); - } else { - SSVAL(p,0,0); - *(p+2) = 0; - } - p += 2 + 24; - /* nameptr = p; */ - pstrcpy(p,fname); p += strlen(p); - p = pdata + len; - break; - - case SMB_FIND_FILE_DIRECTORY_INFO: - len = 64+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date(p,cdate); p += 8; - put_long_date(p,adate); p += 8; - put_long_date(p,mdate); p += 8; - put_long_date(p,mdate); p += 8; - SOFF_T(p,0,size); - SOFF_T(p,8,size); - p += 16; - SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - pstrcpy(p,fname); - p = pdata + len; - break; - + found = True; + } + } + + name_map_mangle(fname,False,True,SNUM(conn)); + + p = pdata; + nameptr = p; + + nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL; + + switch (info_level) { + case 1: + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; + } + put_dos_date2(p,l1_fdateCreation,cdate); + put_dos_date2(p,l1_fdateLastAccess,adate); + put_dos_date2(p,l1_fdateLastWrite,mdate); + SIVAL(p,l1_cbFile,(uint32)size); + SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size); + SSVAL(p,l1_attrFile,mode); + SCVAL(p,l1_cchName,strlen(fname)); + pstrcpy(p + l1_achName, fname); + nameptr = p + l1_achName; + p += l1_achName + strlen(fname) + 1; + break; + + case 2: + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; + } + put_dos_date2(p,l2_fdateCreation,cdate); + put_dos_date2(p,l2_fdateLastAccess,adate); + put_dos_date2(p,l2_fdateLastWrite,mdate); + SIVAL(p,l2_cbFile,(uint32)size); + SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size); + SSVAL(p,l2_attrFile,mode); + SIVAL(p,l2_cbList,0); /* No extended attributes */ + SCVAL(p,l2_cchName,strlen(fname)); + pstrcpy(p + l2_achName, fname); + nameptr = p + l2_achName; + p += l2_achName + strlen(fname) + 1; + break; + + case 3: + SIVAL(p,0,reskey); + put_dos_date2(p,4,cdate); + put_dos_date2(p,8,adate); + put_dos_date2(p,12,mdate); + SIVAL(p,16,(uint32)size); + SIVAL(p,20,(uint32)allocation_size); + SSVAL(p,24,mode); + SIVAL(p,26,4); + SCVAL(p,30,strlen(fname)); + pstrcpy(p+31, fname); + nameptr = p+31; + p += 31 + strlen(fname) + 1; + break; + + case 4: + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; + } + SIVAL(p,0,33+strlen(fname)+1); + put_dos_date2(p,4,cdate); + put_dos_date2(p,8,adate); + put_dos_date2(p,12,mdate); + SIVAL(p,16,(uint32)size); + SIVAL(p,20,(uint32)allocation_size); + SSVAL(p,24,mode); + SCVAL(p,32,strlen(fname)); + pstrcpy(p + 33, fname); + nameptr = p+33; + p += 33 + strlen(fname) + 1; + break; + + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + was_8_3 = is_8_3(fname, True); + len = 94+strlen(fname); + len = (len + 3) & ~3; + SIVAL(p,0,len); p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date(p,cdate); p += 8; + put_long_date(p,adate); p += 8; + put_long_date(p,mdate); p += 8; + put_long_date(p,mdate); p += 8; + SOFF_T(p,0,size); + SOFF_T(p,8,allocation_size); + p += 16; + SIVAL(p,0,nt_extmode); p += 4; + SIVAL(p,0,strlen(fname)); p += 4; + SIVAL(p,0,0); p += 4; + if (!was_8_3) { + fstrcpy(p+2,fname); + if(!name_map_mangle(p+2,True,True,SNUM(conn))) + (p+2)[12] = 0; + strupper(p+2); + SSVAL(p, 0, strlen(p+2)); + } else { + SSVAL(p,0,0); + *(p+2) = 0; + } + p += 2 + 24; + /* nameptr = p; */ + pstrcpy(p,fname); p += strlen(p); + p = pdata + len; + break; + + case SMB_FIND_FILE_DIRECTORY_INFO: + len = 64+strlen(fname); + len = (len + 3) & ~3; + SIVAL(p,0,len); p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date(p,cdate); p += 8; + put_long_date(p,adate); p += 8; + put_long_date(p,mdate); p += 8; + put_long_date(p,mdate); p += 8; + SOFF_T(p,0,size); + SOFF_T(p,8,allocation_size); + p += 16; + SIVAL(p,0,nt_extmode); p += 4; + SIVAL(p,0,strlen(fname)); p += 4; + pstrcpy(p,fname); + p = pdata + len; + break; - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - len = 68+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date(p,cdate); p += 8; - put_long_date(p,adate); p += 8; - put_long_date(p,mdate); p += 8; - put_long_date(p,mdate); p += 8; - SOFF_T(p,0,size); - SOFF_T(p,8,size); - p += 16; - SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - SIVAL(p,0,0); p += 4; - pstrcpy(p,fname); - p = pdata + len; - break; - - case SMB_FIND_FILE_NAMES_INFO: - len = 12+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - pstrcpy(p,fname); - p = pdata + len; - break; - - default: - return(False); - } - - - if (PTR_DIFF(p,pdata) > space_remaining) { - /* Move the dirptr back to prev_dirpos */ - SeekDir(conn->dirptr, prev_dirpos); - *out_of_space = True; - DEBUG(9,("get_lanman2_dir_entry: out of space\n")); - return False; /* Not finished - just out of space */ - } - - /* Setup the last_filename pointer, as an offset from base_data */ - *last_name_off = PTR_DIFF(nameptr,base_data); - /* Advance the data pointer to the next slot */ - *ppdata = p; - - return(found); + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + len = 68+strlen(fname); + len = (len + 3) & ~3; + SIVAL(p,0,len); p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date(p,cdate); p += 8; + put_long_date(p,adate); p += 8; + put_long_date(p,mdate); p += 8; + put_long_date(p,mdate); p += 8; + SOFF_T(p,0,size); + SOFF_T(p,8,allocation_size); + p += 16; + SIVAL(p,0,nt_extmode); p += 4; + SIVAL(p,0,strlen(fname)); p += 4; + SIVAL(p,0,0); p += 4; + pstrcpy(p,fname); + p = pdata + len; + break; + + case SMB_FIND_FILE_NAMES_INFO: + len = 12+strlen(fname); + len = (len + 3) & ~3; + SIVAL(p,0,len); p += 4; + SIVAL(p,0,reskey); p += 4; + SIVAL(p,0,strlen(fname)); p += 4; + pstrcpy(p,fname); + p = pdata + len; + break; + + /* CIFS UNIX Extension. */ + + case SMB_FIND_FILE_UNIX: + len = 108+strlen(fname)+1; /* (length of SMB_QUERY_FILE_UNIX_BASIC = 100)+4+4+strlen(fname)*/ + /* +1 to be sure to transmit the termination of fname */ + len = (len + 3) & ~3; + + SIVAL(p,0,len); p+= 4; /* Offset from this structure to the beginning of the next one */ + SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ + + /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ + SOFF_T(p,0,sbuf.st_size); /* File size 64 Bit */ + p+= 8; + +#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) + SOFF_T(p,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ +#else + /* Can't get the value - fake it using size. */ + SOFF_T(p,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */ +#endif + p+= 8; + + put_long_date(p,sbuf.st_ctime); /* Creation Time 64 Bit */ + put_long_date(p+8,sbuf.st_atime); /* Last access time 64 Bit */ + put_long_date(p+16,sbuf.st_mtime); /* Last modification time 64 Bit */ + p+= 24; + + SIVAL(p,0,sbuf.st_uid); /* user id for the owner */ + SIVAL(p,4,0); + p+= 8; + + SIVAL(p,0,sbuf.st_gid); /* group id of owner */ + SIVAL(p,4,0); + p+= 8; + + SIVAL(p,0,unix_filetype(sbuf.st_mode)); + p+= 4; + + SIVAL(p,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */ + SIVAL(p,4,0); + p+= 8; + + SIVAL(p,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */ + SIVAL(p,4,0); + p+= 8; + + SINO_T(p,0,(SMB_INO_T)sbuf.st_ino); /* inode number */ + p+= 8; + + SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */ + SIVAL(p,4,0); + p+= 8; + + SIVAL(p,0,sbuf.st_nlink); /* number of hard links */ + SIVAL(p,4,0); + p+= 8; + + /* End of SMB_QUERY_FILE_UNIX_BASIC */ + pstrcpy(p,fname); + p=pdata+len; + + break; + + default: + return(False); + } + + + if (PTR_DIFF(p,pdata) > space_remaining) { + /* Move the dirptr back to prev_dirpos */ + SeekDir(conn->dirptr, prev_dirpos); + *out_of_space = True; + DEBUG(9,("get_lanman2_dir_entry: out of space\n")); + return False; /* Not finished - just out of space */ + } + + /* Setup the last_filename pointer, as an offset from base_data */ + *last_name_off = PTR_DIFF(nameptr,base_data); + /* Advance the data pointer to the next slot */ + *ppdata = p; + + return(found); } - /**************************************************************************** Reply to a TRANS2_FINDFIRST. ****************************************************************************/ -static int call_trans2findfirst(connection_struct *conn, - char *inbuf, char *outbuf, int bufsize, - char **pparams, char **ppdata) +static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dirtype = SVAL(params,0); - int maxentries = SVAL(params,2); - BOOL close_after_first = BITSETW(params+4,0); - BOOL close_if_end = BITSETW(params+4,1); - BOOL requires_resume_key = BITSETW(params+4,2); - int info_level = SVAL(params,6); - pstring directory; - pstring mask; - char *p, *wcard; - int last_name_off=0; - int dptr_num = -1; - int numentries = 0; - int i; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - - *directory = *mask = 0; - - DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", - dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, - info_level, max_data_bytes)); + /* We must be careful here that we don't return more than the + allowed number of data bytes. If this means returning fewer than + maxentries then so be it. We assume that the redirector has + enough room for the fixed number of parameter bytes it has + requested. */ + uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *params = *pparams; + char *pdata = *ppdata; + int dirtype; + int maxentries; + BOOL close_after_first; + BOOL close_if_end; + BOOL requires_resume_key; + int info_level; + pstring directory; + pstring mask; + char *p, *wcard; + int last_name_off=0; + int dptr_num = -1; + int numentries = 0; + int i; + BOOL finished = False; + BOOL dont_descend = False; + BOOL out_of_space = False; + int space_remaining; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + + if (total_params < 12) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + *directory = *mask = 0; + + dirtype = SVAL(params,0); + maxentries = SVAL(params,2); + close_after_first = BITSETW(params+4,0); + close_if_end = BITSETW(params+4,1); + requires_resume_key = BITSETW(params+4,2); + info_level = SVAL(params,6); + + DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \ +close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", + dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, + info_level, max_data_bytes)); - switch (info_level) - { - case 1: - case 2: - case 3: - case 4: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - pstrcpy(directory, params + 12); /* Complete directory path with - wildcard mask appended */ - - RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); - - DEBUG(5,("path=%s\n",directory)); - - unix_convert(directory,conn,0,&bad_path,&sbuf); - if(!check_name(directory,conn)) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + switch (info_level) { + case 1: + case 2: + case 3: + case 4: + case SMB_FIND_FILE_DIRECTORY_INFO: + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + case SMB_FIND_FILE_NAMES_INFO: + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + break; + case SMB_FIND_FILE_UNIX: + if (!lp_unix_extensions()) + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + break; + default: + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + } + + pstrcpy(directory, params + 12); /* Complete directory path with wildcard mask appended */ + + RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); + + DEBUG(5,("path=%s\n",directory)); + + unix_convert(directory,conn,0,&bad_path,&sbuf); + if(!check_name(directory,conn)) { + set_bad_path_error(errno, bad_path); #if 0 - /* Ugly - NT specific hack - maybe not needed ? (JRA) */ - if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && - (get_remote_arch() == RA_WINNT)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbaddirectory; - } + /* Ugly - NT specific hack - maybe not needed ? (JRA) */ + if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && (get_remote_arch() == RA_WINNT)) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbaddirectory; + } #endif - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - p = strrchr(directory,'/'); - if(p == NULL) { - pstrcpy(mask,directory); - pstrcpy(directory,"./"); - } else { - pstrcpy(mask,p+1); - *p = 0; - } - - DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); - - pdata = Realloc(*ppdata, max_data_bytes + 1024); - if( pdata == NULL ) { - return(ERROR(ERRDOS,ERRnomem)); - } - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - /* Realloc the params space */ - params = Realloc(*pparams, 10); - if( params == NULL ) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; - - dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid)); - if (dptr_num < 0) - return(UNIXERROR(ERRDOS,ERRbadfile)); - - /* Save the wildcard match and attribs we are using on this directory - - needed as lanman2 assumes these are being saved between calls */ - - if(!(wcard = strdup(mask))) { - dptr_close(&dptr_num); - return(ERROR(ERRDOS,ERRnomem)); - } - - dptr_set_wcard(dptr_num, wcard); - dptr_set_attr(dptr_num, dirtype); - - DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + + p = strrchr(directory,'/'); + if(p == NULL) { + pstrcpy(mask,directory); + pstrcpy(directory,"./"); + } else { + pstrcpy(mask,p+1); + *p = 0; + } + + DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); + + pdata = Realloc(*ppdata, max_data_bytes + 1024); + if( pdata == NULL ) + return(ERROR_DOS(ERRDOS,ERRnomem)); + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + /* Realloc the params space */ + params = Realloc(*pparams, 10); + if( params == NULL ) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid)); + if (dptr_num < 0) + return(UNIXERROR(ERRDOS,ERRbadfile)); + + /* Save the wildcard match and attribs we are using on this directory - + needed as lanman2 assumes these are being saved between calls */ + + if(!(wcard = strdup(mask))) { + dptr_close(&dptr_num); + return ERROR_DOS(ERRDOS,ERRnomem); + } + + dptr_set_wcard(dptr_num, wcard); + dptr_set_attr(dptr_num, dirtype); + + DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); + + /* We don't need to check for VOL here as this is returned by + a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) - dont_descend = True; + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); + + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + dont_descend = True; - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - for (i=0;(i<maxentries) && !finished && !out_of_space;i++) - { - BOOL got_exact_match = False; - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) - { - out_of_space = True; - finished = False; - } - else - { - finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level, - requires_resume_key,dont_descend, - &p,pdata,space_remaining, &out_of_space, &got_exact_match, - &last_name_off); - } - - if (finished && out_of_space) - finished = False; - - if (!finished && !out_of_space) - numentries++; - - /* - * As an optimisation if we know we aren't looking - * for a wildcard name (ie. the name matches the wildcard exactly) - * then we can finish on any (first) match. - * This speeds up large directory searches. JRA. - */ - - if(got_exact_match) - finished = True; - - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } + p = pdata; + space_remaining = max_data_bytes; + out_of_space = False; + + for (i=0;(i<maxentries) && !finished && !out_of_space;i++) { + BOOL got_exact_match = False; + + /* this is a heuristic to avoid seeking the dirptr except when + absolutely necessary. It allows for a filename of about 40 chars */ + + if (space_remaining < DIRLEN_GUESS && numentries > 0) { + out_of_space = True; + finished = False; + } else { + finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level, + requires_resume_key,dont_descend, + &p,pdata,space_remaining, &out_of_space, &got_exact_match, + &last_name_off); + } + + if (finished && out_of_space) + finished = False; + + if (!finished && !out_of_space) + numentries++; + + /* + * As an optimisation if we know we aren't looking + * for a wildcard name (ie. the name matches the wildcard exactly) + * then we can finish on any (first) match. + * This speeds up large directory searches. JRA. + */ + + if(got_exact_match) + finished = True; + + space_remaining = max_data_bytes - PTR_DIFF(p,pdata); + } - /* Check if we can close the dirptr */ - if(close_after_first || (finished && close_if_end)) - { - DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_close(&dptr_num); - } - - /* - * If there are no matching entries we must return ERRDOS/ERRbadfile - - * from observation of NT. - */ - - if(numentries == 0) - { - dptr_close(&dptr_num); - return(ERROR(ERRDOS,ERRbadfile)); - } - - /* At this point pdata points to numentries directory entries. */ - - /* Set up the return parameter block */ - SSVAL(params,0,dptr_num); - SSVAL(params,2,numentries); - SSVAL(params,4,finished); - SSVAL(params,6,0); /* Never an EA error */ - SSVAL(params,8,last_name_off); - - send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); - - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - - DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); - - /* - * Force a name mangle here to ensure that the - * mask as an 8.3 name is top of the mangled cache. - * The reasons for this are subtle. Don't remove - * this code unless you know what you are doing - * (see PR#13758). JRA. - */ - - if(!is_8_3( mask, False)) - name_map_mangle(mask, True, True, SNUM(conn)); - - return(-1); -} + /* Check if we can close the dirptr */ + + if(close_after_first || (finished && close_if_end)) { + DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); + dptr_close(&dptr_num); + } + + /* + * If there are no matching entries we must return ERRDOS/ERRbadfile - + * from observation of NT. + */ + + if(numentries == 0) { + dptr_close(&dptr_num); + return ERROR_DOS(ERRDOS,ERRbadfile); + } + + /* At this point pdata points to numentries directory entries. */ + + /* Set up the return parameter block */ + SSVAL(params,0,dptr_num); + SSVAL(params,2,numentries); + SSVAL(params,4,finished); + SSVAL(params,6,0); /* Never an EA error */ + SSVAL(params,8,last_name_off); + + send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); + if ((! *directory) && dptr_path(dptr_num)) + slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + + DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); + + /* + * Force a name mangle here to ensure that the + * mask as an 8.3 name is top of the mangled cache. + * The reasons for this are subtle. Don't remove + * this code unless you know what you are doing + * (see PR#13758). JRA. + */ + + if(!is_8_3( mask, False)) + name_map_mangle(mask, True, True, SNUM(conn)); + + return(-1); +} /**************************************************************************** - reply to a TRANS2_FINDNEXT + Reply to a TRANS2_FINDNEXT. ****************************************************************************/ -static int call_trans2findnext(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) + +static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dptr_num = SVAL(params,0); - int maxentries = SVAL(params,2); - uint16 info_level = SVAL(params,4); - uint32 resume_key = IVAL(params,6); - BOOL close_after_request = BITSETW(params+10,0); - BOOL close_if_end = BITSETW(params+10,1); - BOOL requires_resume_key = BITSETW(params+10,2); - BOOL continue_bit = BITSETW(params+10,3); - pstring resume_name; - pstring mask; - pstring directory; - char *p; - uint16 dirtype; - int numentries = 0; - int i, last_name_off=0; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - - *mask = *directory = *resume_name = 0; - - pstrcpy( resume_name, params+12); - - DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ + /* We must be careful here that we don't return more than the + allowed number of data bytes. If this means returning fewer than + maxentries then so be it. We assume that the redirector has + enough room for the fixed number of parameter bytes it has + requested. */ + int max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *params = *pparams; + char *pdata = *ppdata; + int dptr_num; + int maxentries; + uint16 info_level; + uint32 resume_key; + BOOL close_after_request; + BOOL close_if_end; + BOOL requires_resume_key; + BOOL continue_bit; + pstring resume_name; + pstring mask; + pstring directory; + char *p; + uint16 dirtype; + int numentries = 0; + int i, last_name_off=0; + BOOL finished = False; + BOOL dont_descend = False; + BOOL out_of_space = False; + int space_remaining; + + if (total_params < 12) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + dptr_num = SVAL(params,0); + maxentries = SVAL(params,2); + info_level = SVAL(params,4); + resume_key = IVAL(params,6); + close_after_request = BITSETW(params+10,0); + close_if_end = BITSETW(params+10,1); + requires_resume_key = BITSETW(params+10,2); + continue_bit = BITSETW(params+10,3); + + *mask = *directory = *resume_name = 0; + + pstrcpy( resume_name, params+12); + + DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ close_after_request=%d, close_if_end = %d requires_resume_key = %d \ resume_key = %d resume name = %s continue=%d level = %d\n", - dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, - requires_resume_key, resume_key, resume_name, continue_bit, info_level)); - - switch (info_level) - { - case 1: - case 2: - case 3: - case 4: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - pdata = Realloc( *ppdata, max_data_bytes + 1024); - if(pdata == NULL) { - return(ERROR(ERRDOS,ERRnomem)); - } - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - /* Realloc the params space */ - params = Realloc(*pparams, 6*SIZEOFWORD); - if( params == NULL ) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; - - /* Check that the dptr is valid */ - if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) - return(ERROR(ERRDOS,ERRnofiles)); - - string_set(&conn->dirpath,dptr_path(dptr_num)); - - /* Get the wildcard mask from the dptr */ - if((p = dptr_wcard(dptr_num))== NULL) { - DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - return (ERROR(ERRDOS,ERRnofiles)); - } - pstrcpy(mask, p); - pstrcpy(directory,conn->dirpath); - - /* Get the attr mask from the dptr */ - dirtype = dptr_attr(dptr_num); - - DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n", - dptr_num, mask, dirtype, - (long)conn->dirptr, - TellDir(conn->dirptr))); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ - - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) - dont_descend = True; + dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, + requires_resume_key, resume_key, resume_name, continue_bit, info_level)); + + switch (info_level) { + case 1: + case 2: + case 3: + case 4: + case SMB_FIND_FILE_DIRECTORY_INFO: + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + case SMB_FIND_FILE_NAMES_INFO: + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + break; + case SMB_FIND_FILE_UNIX: + if (!lp_unix_extensions()) + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + break; + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + pdata = Realloc( *ppdata, max_data_bytes + 1024); + if(pdata == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + /* Realloc the params space */ + params = Realloc(*pparams, 6*SIZEOFWORD); + if( params == NULL ) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + /* Check that the dptr is valid */ + if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) + return ERROR_DOS(ERRDOS,ERRnofiles); + + string_set(&conn->dirpath,dptr_path(dptr_num)); + + /* Get the wildcard mask from the dptr */ + if((p = dptr_wcard(dptr_num))== NULL) { + DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); + return ERROR_DOS(ERRDOS,ERRnofiles); + } + pstrcpy(mask, p); + pstrcpy(directory,conn->dirpath); + + /* Get the attr mask from the dptr */ + dirtype = dptr_attr(dptr_num); + + DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n", + dptr_num, mask, dirtype, (long)conn->dirptr, TellDir(conn->dirptr))); + + /* We don't need to check for VOL here as this is returned by + a different TRANS2 call. */ + + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + dont_descend = True; - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - /* - * Seek to the correct position. We no longer use the resume key but - * depend on the last file name instead. - */ - if(requires_resume_key && *resume_name && !continue_bit) - { - /* - * Fix for NT redirector problem triggered by resume key indexes - * changing between directory scans. We now return a resume key of 0 - * and instead look for the filename to continue from (also given - * to us by NT/95/smbfs/smbclient). If no other scans have been done between the - * findfirst/findnext (as is usual) then the directory pointer - * should already be at the correct place. Check this by scanning - * backwards looking for an exact (ie. case sensitive) filename match. - * If we get to the beginning of the directory and haven't found it then scan - * forwards again looking for a match. JRA. - */ - - int current_pos, start_pos; - char *dname = NULL; - void *dirptr = conn->dirptr; - start_pos = TellDir(dirptr); - for(current_pos = start_pos; current_pos >= 0; current_pos--) - { - DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos)); - - SeekDir(dirptr, current_pos); - dname = ReadDirName(dirptr); - - /* - * Remember, name_map_mangle is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname != NULL) - name_map_mangle( dname, False, True, SNUM(conn)); - - if(dname && strcsequal( resume_name, dname)) - { - SeekDir(dirptr, current_pos+1); - DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); - break; - } - } - - /* - * Scan forward from start if not found going backwards. - */ - - if(current_pos < 0) - { - DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos)); - SeekDir(dirptr, start_pos); - for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) - { - /* - * Remember, name_map_mangle is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname != NULL) - name_map_mangle( dname, False, True, SNUM(conn)); - - if(dname && strcsequal( resume_name, dname)) - { - SeekDir(dirptr, current_pos+1); - DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); - break; - } - } /* end for */ - } /* end if current_pos */ - } /* end if requires_resume_key && !continue_bit */ - - for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) - { - BOOL got_exact_match = False; - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) - { - out_of_space = True; - finished = False; - } - else - { - finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level, - requires_resume_key,dont_descend, - &p,pdata,space_remaining, &out_of_space, &got_exact_match, - &last_name_off); - } - - if (finished && out_of_space) - finished = False; - - if (!finished && !out_of_space) - numentries++; - - /* - * As an optimisation if we know we aren't looking - * for a wildcard name (ie. the name matches the wildcard exactly) - * then we can finish on any (first) match. - * This speeds up large directory searches. JRA. - */ - - if(got_exact_match) - finished = True; - - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } + p = pdata; + space_remaining = max_data_bytes; + out_of_space = False; + + /* + * Seek to the correct position. We no longer use the resume key but + * depend on the last file name instead. + */ + + if(requires_resume_key && *resume_name && !continue_bit) { + + /* + * Fix for NT redirector problem triggered by resume key indexes + * changing between directory scans. We now return a resume key of 0 + * and instead look for the filename to continue from (also given + * to us by NT/95/smbfs/smbclient). If no other scans have been done between the + * findfirst/findnext (as is usual) then the directory pointer + * should already be at the correct place. Check this by scanning + * backwards looking for an exact (ie. case sensitive) filename match. + * If we get to the beginning of the directory and haven't found it then scan + * forwards again looking for a match. JRA. + */ + + int current_pos, start_pos; + char *dname = NULL; + void *dirptr = conn->dirptr; + start_pos = TellDir(dirptr); + + for(current_pos = start_pos; current_pos >= 0; current_pos--) { + DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos)); + + SeekDir(dirptr, current_pos); + dname = ReadDirName(dirptr); + + /* + * Remember, name_map_mangle is called by + * get_lanman2_dir_entry(), so the resume name + * could be mangled. Ensure we do the same + * here. + */ + + if(dname != NULL) + name_map_mangle( dname, False, True, SNUM(conn)); + + if(dname && strcsequal( resume_name, dname)) { + SeekDir(dirptr, current_pos+1); + DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); + break; + } + } + + /* + * Scan forward from start if not found going backwards. + */ + + if(current_pos < 0) { + DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos)); + SeekDir(dirptr, start_pos); + for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) { + + /* + * Remember, name_map_mangle is called by + * get_lanman2_dir_entry(), so the resume name + * could be mangled. Ensure we do the same + * here. + */ + + if(dname != NULL) + name_map_mangle( dname, False, True, SNUM(conn)); + + if(dname && strcsequal( resume_name, dname)) { + SeekDir(dirptr, current_pos+1); + DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); + break; + } + } /* end for */ + } /* end if current_pos */ + } /* end if requires_resume_key && !continue_bit */ + + for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) { + BOOL got_exact_match = False; + + /* this is a heuristic to avoid seeking the dirptr except when + absolutely necessary. It allows for a filename of about 40 chars */ + + if (space_remaining < DIRLEN_GUESS && numentries > 0) { + out_of_space = True; + finished = False; + } else { + finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level, + requires_resume_key,dont_descend, + &p,pdata,space_remaining, &out_of_space, &got_exact_match, + &last_name_off); + } + + if (finished && out_of_space) + finished = False; + + if (!finished && !out_of_space) + numentries++; + + /* + * As an optimisation if we know we aren't looking + * for a wildcard name (ie. the name matches the wildcard exactly) + * then we can finish on any (first) match. + * This speeds up large directory searches. JRA. + */ + + if(got_exact_match) + finished = True; + + space_remaining = max_data_bytes - PTR_DIFF(p,pdata); + } - /* Check if we can close the dirptr */ - if(close_after_request || (finished && close_if_end)) - { - DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_close(&dptr_num); /* This frees up the saved mask */ - } + /* Check if we can close the dirptr */ + if(close_after_request || (finished && close_if_end)) { + DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); + dptr_close(&dptr_num); /* This frees up the saved mask */ + } - /* Set up the return parameter block */ - SSVAL(params,0,numentries); - SSVAL(params,2,finished); - SSVAL(params,4,0); /* Never an EA error */ - SSVAL(params,6,last_name_off); + /* Set up the return parameter block */ + SSVAL(params,0,numentries); + SSVAL(params,2,finished); + SSVAL(params,4,0); /* Never an EA error */ + SSVAL(params,6,last_name_off); - send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); + send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + if ((! *directory) && dptr_path(dptr_num)) + slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); + DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); - return(-1); + return(-1); } /**************************************************************************** - reply to a TRANS2_QFSINFO (query filesystem info) + Reply to a TRANS2_QFSINFO (query filesystem info). ****************************************************************************/ -static int call_trans2qfsinfo(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) +static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *pdata = *ppdata; - char *params = *pparams; - uint16 info_level = SVAL(params,0); - int data_len; - SMB_STRUCT_STAT st; - char *vname = volume_label(SNUM(conn)); - int snum = SNUM(conn); - char *fstype = lp_fstype(SNUM(conn)); - - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - - if(vfs_stat(conn,".",&st)!=0) { - DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); - return (ERROR(ERRSRV,ERRinvdevice)); - } - - pdata = Realloc(*ppdata, max_data_bytes + 1024); - if ( pdata == NULL ) { - return(ERROR(ERRDOS,ERRnomem)); - } - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - switch (info_level) - { - case 1: - { - SMB_BIG_UINT dfree,dsize,bsize; - data_len = 18; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - SIVAL(pdata,l1_idFileSystem,st.st_dev); - SIVAL(pdata,l1_cSectorUnit,bsize/512); - SIVAL(pdata,l1_cUnit,dsize); - SIVAL(pdata,l1_cUnitAvail,dfree); - SSVAL(pdata,l1_cbSector,512); - DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n", - (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize, - (unsigned int)dfree, 512)); - break; - } - case 2: - { - /* Return volume name */ - int volname_len = MIN(strlen(vname),11); - data_len = l2_vol_szVolLabel + volname_len + 1; - /* - * Add volume serial number - hash of a combination of - * the called hostname and the service name. - */ - SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); - SCVAL(pdata,l2_vol_cch,volname_len); - StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len); - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", - (unsigned)st.st_ctime, volname_len, - pdata+l2_vol_szVolLabel)); - break; - } - case SMB_QUERY_FS_ATTRIBUTE_INFO: - { - int fstype_len; - SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| - FILE_DEVICE_IS_MOUNTED| - (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ + int max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *pdata = *ppdata; + char *params = *pparams; + uint16 info_level; + int data_len; + SMB_STRUCT_STAT st; + char *vname = volume_label(SNUM(conn)); + int snum = SNUM(conn); + char *fstype = lp_fstype(SNUM(conn)); + + if (total_params < 2) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + info_level = SVAL(params,0); + DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + + if(vfs_stat(conn,".",&st)!=0) { + DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); + return ERROR_DOS(ERRSRV,ERRinvdevice); + } + + pdata = Realloc(*ppdata, max_data_bytes + 1024); + if ( pdata == NULL ) + return ERROR_DOS(ERRDOS,ERRnomem); + + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + switch (info_level) { + case 1: + { + SMB_BIG_UINT dfree,dsize,bsize; + data_len = 18; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SIVAL(pdata,l1_idFileSystem,st.st_dev); + SIVAL(pdata,l1_cSectorUnit,bsize/512); + SIVAL(pdata,l1_cUnit,dsize); + SIVAL(pdata,l1_cUnitAvail,dfree); + SSVAL(pdata,l1_cbSector,512); + DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n", + (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize, + (unsigned int)dfree, 512)); + break; + } + + case 2: + { + /* Return volume name */ + int volname_len = MIN(strlen(vname),11); + data_len = l2_vol_szVolLabel + volname_len + 1; + /* + * Add volume serial number - hash of a combination of + * the called hostname and the service name. + */ + SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); + SCVAL(pdata,l2_vol_cch,volname_len); + StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len); + DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", + (unsigned)st.st_ctime, volname_len, + pdata+l2_vol_szVolLabel)); + break; + } + + case SMB_QUERY_FS_ATTRIBUTE_INFO: + case SMB_FS_ATTRIBUTE_INFORMATION: + { + int fstype_len; + SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| + (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ #if 0 /* Old code. JRA. */ - SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */ - SIVAL(pdata,0,0x700FF); + SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */ + SIVAL(pdata,0,0x700FF); #endif /* Old code. */ - SIVAL(pdata,4,255); /* Max filename component length */ - fstype_len = dos_PutUniCode(pdata+12,unix_to_dos(fstype,False),sizeof(pstring), False); - SIVAL(pdata,8,fstype_len); - data_len = 12 + fstype_len; - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS); - break; - } - case SMB_QUERY_FS_LABEL_INFO: - data_len = 4 + strlen(vname); - SIVAL(pdata,0,strlen(vname)); - pstrcpy(pdata+4,vname); - break; - case SMB_QUERY_FS_VOLUME_INFO: - - /* - * Add volume serial number - hash of a combination of - * the called hostname and the service name. - */ - SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ - (str_checksum(local_machine)<<16)); - - /* NT4 always serves this up as unicode but expects it to be - * delivered as ascii! (tridge && JRA) - */ - if ((get_remote_arch() != RA_WIN2K) && (global_client_caps & CAP_NT_SMBS)) { - data_len = 18 + strlen(vname); - SIVAL(pdata,12,strlen(vname)); - pstrcpy(pdata+18,vname); - } else { - int vnamelen; - - vnamelen = dos_PutUniCode(pdata+18, vname, sizeof(pstring), False); - data_len = 18 + vnamelen; - SIVAL(pdata,12,vnamelen); - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS); - } - - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", - (int)strlen(vname),vname)); - break; - case SMB_QUERY_FS_SIZE_INFO: - { - SMB_BIG_UINT dfree,dsize,bsize; - data_len = 24; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - SBIG_UINT(pdata,0,dsize); - SBIG_UINT(pdata,8,dfree); - SIVAL(pdata,16,bsize/512); - SIVAL(pdata,20,512); - break; - } - case SMB_QUERY_FS_DEVICE_INFO: - data_len = 8; - SIVAL(pdata,0,0); /* dev type */ - SIVAL(pdata,4,0); /* characteristics */ - break; - case SMB_MAC_QUERY_FS_INFO: - /* - * Thursby MAC extension... ONLY on NTFS filesystems - * once we do streams then we don't need this - */ - if (strequal(lp_fstype(SNUM(conn)),"NTFS")) { - data_len = 88; - SIVAL(pdata,84,0x100); /* Don't support mac... */ - break; - } - /* drop through */ - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - - send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); - - DEBUG( 4, ( "%s info_level = %d\n", - smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); - - return -1; + SIVAL(pdata,4,255); /* Max filename component length */ + /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it + and will think we can't do long filenames */ + fstype_len = dos_PutUniCode(pdata+12,unix_to_dos(fstype,False),sizeof(pstring), False); + SIVAL(pdata,8,fstype_len); + data_len = 12 + fstype_len; + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS); + break; + } + + case SMB_QUERY_FS_LABEL_INFO: + case SMB_FS_LABEL_INFORMATION: + data_len = 4 + strlen(vname); + SIVAL(pdata,0,strlen(vname)); + pstrcpy(pdata+4,vname); + break; + + case SMB_QUERY_FS_VOLUME_INFO: + case SMB_FS_VOLUME_INFORMATION: + /* + * Add volume serial number - hash of a combination of + * the called hostname and the service name. + */ + SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ + (str_checksum(local_machine)<<16)); + + /* NT4 always serves this up as unicode but expects it to be + * delivered as ascii! (tridge && JRA) + */ + if ((get_remote_arch() != RA_WIN2K) && (global_client_caps & CAP_NT_SMBS)) { + data_len = 18 + strlen(vname); + SIVAL(pdata,12,strlen(vname)); + pstrcpy(pdata+18,vname); + } else { + int vnamelen; + + vnamelen = dos_PutUniCode(pdata+18, vname, sizeof(pstring), False); + data_len = 18 + vnamelen; + SIVAL(pdata,12,vnamelen); + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS); + } + + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", + (int)strlen(vname),vname)); + break; + + case SMB_QUERY_FS_SIZE_INFO: + case SMB_FS_SIZE_INFORMATION: + { + SMB_BIG_UINT dfree,dsize,bsize; + data_len = 24; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SBIG_UINT(pdata,0,dsize); + SBIG_UINT(pdata,8,dfree); + SIVAL(pdata,16,bsize/512); + SIVAL(pdata,20,512); + break; + } + + case SMB_FS_FULL_SIZE_INFORMATION: + { + SMB_BIG_UINT dfree,dsize,bsize; + data_len = 32; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SBIG_UINT(pdata,0,dsize); + SBIG_UINT(pdata,8,dsize); + SBIG_UINT(pdata,16,dfree); + SIVAL(pdata,24,bsize/512); + SIVAL(pdata,28,512); + break; + } + + case SMB_QUERY_FS_DEVICE_INFO: + case SMB_FS_DEVICE_INFORMATION: + data_len = 8; + SIVAL(pdata,0,0); /* dev type */ + SIVAL(pdata,4,0); /* characteristics */ + break; + + case SMB_FS_OBJECTID_INFORMATION: + data_len = 64; + break; + + /* + * Query the version and capabilities of the CIFS UNIX extensions + * in use. + */ + + case SMB_QUERY_CIFS_UNIX_INFO: + + if (!lp_unix_extensions()) + return ERROR_DOS(ERRDOS,ERRunknownlevel); + + data_len = 12; + SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION); + SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION); + SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */ + break; + + case SMB_MAC_QUERY_FS_INFO: + /* + * Thursby MAC extension... ONLY on NTFS filesystems + * once we do streams then we don't need this + */ + if (strequal(lp_fstype(SNUM(conn)),"NTFS")) { + data_len = 88; + SIVAL(pdata,84,0x100); /* Don't support mac... */ + break; + } + /* drop through */ + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); + + DEBUG( 4, ( "%s info_level = %d\n", smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); + + return -1; } /**************************************************************************** - reply to a TRANS2_SETFSINFO (set filesystem info) + Reply to a TRANS2_SETFSINFO (set filesystem info). ****************************************************************************/ -static int call_trans2setfsinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **pparams, char **ppdata) + +static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - /* Just say yes we did it - there is nothing that - can be set here so it doesn't matter. */ - int outsize; - DEBUG(3,("call_trans2setfsinfo\n")); + /* Just say yes we did it - there is nothing that + can be set here so it doesn't matter. */ + int outsize; + DEBUG(3,("call_trans2setfsinfo\n")); + + if (!CAN_WRITE(conn)) + return(ERROR_DOS(ERRSRV,ERRaccess)); - if (!CAN_WRITE(conn)) - return(ERROR(ERRSRV,ERRaccess)); + outsize = set_message(outbuf,10,0,True); - outsize = set_message(outbuf,10,0,True); + return outsize; +} + +/**************************************************************************** + Utility function to set bad path error. +****************************************************************************/ - return outsize; +void set_bad_path_error(int err, BOOL bad_path) +{ + if((err == ENOENT) && bad_path) { + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadpath; + } } /**************************************************************************** @@ -1291,11 +1522,8 @@ static int call_trans2setfsinfo(connection_struct *conn, file name or file id). ****************************************************************************/ -static int call_trans2qfilepathinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **pparams,char **ppdata, - int total_data) +static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { int max_data_bytes = SVAL(inbuf, smb_mdrcnt); char *params = *pparams; @@ -1304,10 +1532,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn, uint16 info_level; int mode=0; SMB_OFF_T size=0; + SMB_OFF_T allocation_size=0; unsigned int data_size; SMB_STRUCT_STAT sbuf; pstring fname1; char *fname; + char *fullpathname; char *p; int l; SMB_OFF_T pos = 0; @@ -1316,7 +1546,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn, time_t c_time; if (tran_call == TRANSACT2_QFILEINFO) { - files_struct *fsp = file_fsp(params,0); + files_struct *fsp; + + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + fsp = file_fsp(params,0); info_level = SVAL(params,2); DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); @@ -1329,14 +1564,22 @@ static int call_trans2qfilepathinfo(connection_struct *conn, */ fname = fsp->fsp_name; unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || - (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); + if (!check_name(fname,conn)) { + DEBUG(3,("call_trans2qfilepathinfo: check_name of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (vfs_lstat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); } + } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -1361,6 +1604,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, } } else { /* qpathinfo */ + if (total_params < 6) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + info_level = SVAL(params,0); DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); @@ -1371,16 +1617,29 @@ static int call_trans2qfilepathinfo(connection_struct *conn, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; + if (!check_name(fname,conn)) { + DEBUG(3,("call_trans2qfilepathinfo: check_name of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (vfs_lstat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); } + } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } } + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) + return ERROR_DOS(ERRDOS,ERRunknownlevel); + DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n", fname,info_level,tran_call,total_data)); @@ -1391,7 +1650,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, p++; l = strlen(p); mode = dos_mode(conn,fname,&sbuf); + fullpathname = fname; size = sbuf.st_size; + allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size); if (mode & aDIR) size = 0; @@ -1400,19 +1661,19 @@ static int call_trans2qfilepathinfo(connection_struct *conn, params = Realloc(*pparams,2); if ( params == NULL ) - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); *pparams = params; memset((char *)params,'\0',2); data_size = max_data_bytes + 1024; pdata = Realloc(*ppdata, data_size); if ( pdata == NULL ) - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); *ppdata = pdata; if (total_data > 0 && IVAL(pdata,0) == total_data) { /* uggh, EAs for OS2 */ DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); - return(ERROR(ERRDOS,ERReasnotsupported)); + return ERROR_DOS(ERRDOS,ERReasnotsupported); } memset((char *)pdata,'\0',data_size); @@ -1434,7 +1695,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */ SIVAL(pdata,l1_cbFile,(uint32)size); - SIVAL(pdata,l1_cbFileAlloc,SMB_ROUNDUP(size,1024)); + SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); SSVAL(pdata,l1_attrFile,mode); SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */ break; @@ -1445,7 +1706,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_dos_date2(pdata,4,sbuf.st_atime); put_dos_date2(pdata,8,sbuf.st_mtime); SIVAL(pdata,12,(uint32)size); - SIVAL(pdata,16,SMB_ROUNDUP(size,1024)); + SIVAL(pdata,16,(uint32)allocation_size); SIVAL(pdata,20,mode); break; @@ -1455,7 +1716,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; case 6: - return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */ + return ERROR_DOS(ERRDOS,ERRbadfunc); /* os/2 needs this */ case SMB_FILE_BASIC_INFORMATION: case SMB_QUERY_FILE_BASIC_INFO: @@ -1489,12 +1750,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_FILE_STANDARD_INFORMATION: case SMB_QUERY_FILE_STANDARD_INFO: - data_size = 22; - SOFF_T(pdata,0,size); + data_size = 24; + /* Fake up allocation size. */ + SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,size); SIVAL(pdata,16,sbuf.st_nlink); - CVAL(pdata,20) = 0; - CVAL(pdata,21) = (mode&aDIR)?1:0; + SCVAL(pdata,20,0); + SCVAL(pdata,21,(mode&aDIR)?1:0); break; case SMB_FILE_EA_INFORMATION: @@ -1541,9 +1803,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; case SMB_FILE_ALLOCATION_INFORMATION: - case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_QUERY_FILE_ALLOCATION_INFO: + data_size = 8; + SOFF_T(pdata,0,allocation_size); + break; + case SMB_QUERY_FILE_END_OF_FILEINFO: + case SMB_FILE_END_OF_FILE_INFORMATION: data_size = 8; SOFF_T(pdata,0,size); break; @@ -1555,11 +1821,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_long_date(pdata+24,sbuf.st_mtime); /* change time */ SIVAL(pdata,32,mode); pdata += 40; - SOFF_T(pdata,0,size); + SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,size); SIVAL(pdata,16,sbuf.st_nlink); - CVAL(pdata,20) = delete_pending; - CVAL(pdata,21) = (mode&aDIR)?1:0; + SCVAL(pdata,20,delete_pending); + SCVAL(pdata,21,(mode&aDIR)?1:0); pdata += 24; SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino); pdata += 8; /* index number */ @@ -1608,7 +1874,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_FILE_DISPOSITION_INFORMATION: data_size = 1; - CVAL(pdata,0) = delete_pending; + SCVAL(pdata,0,delete_pending); break; case SMB_FILE_POSITION_INFORMATION: @@ -1668,7 +1934,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SIVAL(pdata,0,0); /* ??? */ SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */ SOFF_T(pdata,8,size); - SIVAL(pdata,16,0x20); /* ??? */ + SIVAL(pdata,16,allocation_size); SIVAL(pdata,20,0); /* ??? */ data_size = 24 + byte_len; } @@ -1686,7 +1952,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, put_long_date(pdata+8,sbuf.st_atime); put_long_date(pdata+16,sbuf.st_mtime); /* write time */ put_long_date(pdata+24,sbuf.st_mtime); /* change time */ - SOFF_T(pdata,32,(SMB_OFF_T)0x20); /* Allocation size. */ + SOFF_T(pdata,32,allocation_size); /* Allocation size. */ SOFF_T(pdata,40,size); SIVAL(pdata,48,mode); SIVAL(pdata,52,0); /* ??? */ @@ -1703,20 +1969,112 @@ static int call_trans2qfilepathinfo(connection_struct *conn, /* * NT4 server just returns "invalid query" to this - if we try to answer * it then NTws gets a BSOD! (tridge). + * W2K seems to want this. JRA. */ case SMB_QUERY_FILE_STREAM_INFO: + if (get_remote_arch() != RA_WIN2K) + return ERROR_DOS(ERRDOS,ERRunknownlevel); data_size = 24 + l; SIVAL(pdata,0,pos); SIVAL(pdata,4,size); - SIVAL(pdata,12,size); + SIVAL(pdata,12,allocation_size); SIVAL(pdata,20,l); pstrcpy(pdata+24,fname); break; #endif + /* + * CIFS UNIX Extensions. + */ + + case SMB_QUERY_FILE_UNIX_BASIC: + + DEBUG(4,("call_trans2qfilepathinfo: st_mode=%o\n",(int)sbuf.st_mode)); + + SOFF_T(pdata,0,sbuf.st_size); /* File size 64 Bit */ + pdata += 8; + +#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) + SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ +#else + /* Can't get the value - fake it using size. */ + SOFF_T(pdata,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */ +#endif + pdata += 8; + + put_long_date(pdata,sbuf.st_ctime); /* Creation Time 64 Bit */ + put_long_date(pdata+8,sbuf.st_atime); /* Last access time 64 Bit */ + put_long_date(pdata+16,sbuf.st_mtime); /* Last modification time 64 Bit */ + pdata += 24; + + SIVAL(pdata,0,sbuf.st_uid); /* user id for the owner */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,sbuf.st_gid); /* group id of owner */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,unix_filetype(sbuf.st_mode)); + pdata += 4; + + SIVAL(pdata,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */ + SIVAL(pdata,4,0); + pdata += 8; + + SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino); /* inode number */ + pdata += 8; + + SIVAL(pdata,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,sbuf.st_nlink); /* number of hard links */ + SIVAL(pdata,4,0); + pdata += 8+1; + data_size = PTR_DIFF(pdata,(*ppdata)); + + { + int i; + DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC")); + + for (i=0; i<100; i++) + DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); + DEBUG(4,("\n")); + } + + break; + + case SMB_QUERY_FILE_UNIX_LINK: + { + pstring buffer; + int len; + +#ifdef S_ISLNK + if(!S_ISLNK(sbuf.st_mode)) + return(UNIXERROR(ERRSRV,ERRbadlink)); +#else + return(UNIXERROR(ERRDOS,ErrNotALink)); +#endif + len = conn->vfs_ops.readlink(conn,dos_to_unix(fullpathname,False), buffer, sizeof(pstring)-1); /* read link */ + if (len == -1) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + buffer[len] = 0; + unix_to_dos(buffer,True); + pstrcpy(pdata,buffer); /* write '\0' terminated string */ + pdata += strlen(buffer)+1; + data_size = PTR_DIFF(pdata,(*ppdata)); + + break; + } + default: - return(ERROR(ERRDOS,ERRunknownlevel)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); } send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size); @@ -1725,619 +2083,906 @@ static int call_trans2qfilepathinfo(connection_struct *conn, } /**************************************************************************** - reply to a TRANS2_SETFILEINFO (set file info by fileid) + Deal with the internal needs of setting the delete on close flag. Note that + as the tdb locking is recursive, it is safe to call this from within + open_file_shared. JRA. ****************************************************************************/ -static int call_trans2setfilepathinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, char **pparams, - char **ppdata, int total_data) + +NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close) { - char *params = *pparams; - char *pdata = *ppdata; - uint16 tran_call = SVAL(inbuf, smb_setup0); - uint16 info_level; - int mode=0; - SMB_OFF_T size=0; - struct utimbuf tvs; - SMB_STRUCT_STAT sbuf; - pstring fname1; - char *fname = NULL; - int fd = -1; - BOOL bad_path = False; - files_struct *fsp = NULL; - - if (tran_call == TRANSACT2_SETFILEINFO) { - fsp = file_fsp(params,0); - info_level = SVAL(params,2); - - if(fsp && (fsp->is_directory || fsp->stat_open)) { - /* - * This is actually a SETFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - fname = fsp->fsp_name; - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - } else if (fsp && fsp->print_file) { - /* - * Doing a DELETE_ON_CLOSE should cancel a print job. - */ - if (((info_level == SMB_SET_FILE_DISPOSITION_INFO)||(info_level == SMB_FILE_DISPOSITION_INFORMATION)) && - CVAL(pdata,0)) { - fsp->share_mode = FILE_DELETE_ON_CLOSE; - - DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", - fsp->fsp_name )); - - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); - } - } else { - /* - * Original code - this is an open file. - */ - CHECK_FSP(fsp,conn); - - fname = fsp->fsp_name; - fd = fsp->fd; - - if (vfs_fstat(fsp,fd,&sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); - return(UNIXERROR(ERRDOS,ERRbadfid)); - } - } - } else { - /* set path info */ - info_level = SVAL(params,0); - fname = fname1; - pstrcpy(fname,¶ms[6]); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if(!check_name(fname, conn)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - if(!VALID_STAT(sbuf)) { - DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - } - - if (!CAN_WRITE(conn)) - return(ERROR(ERRSRV,ERRaccess)); - - DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n", - tran_call,fname,info_level,total_data)); - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,2); - if(params == NULL) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; - - SSVAL(params,0,0); - - size = sbuf.st_size; - tvs.modtime = sbuf.st_mtime; - tvs.actime = sbuf.st_atime; - mode = dos_mode(conn,fname,&sbuf); - - if (total_data > 4 && IVAL(pdata,0) == total_data) { - /* uggh, EAs for OS2 */ - DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); - return(ERROR(ERRDOS,ERReasnotsupported)); - } - - switch (info_level) - { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - { - /* access time */ - tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess); - - /* write time */ - tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite); - - mode = SVAL(pdata,l1_attrFile); - size = IVAL(pdata,l1_cbFile); - break; - } - - /* XXXX um, i don't think this is right. - it's also not in the cifs6.txt spec. - */ - case SMB_INFO_QUERY_EAS_FROM_LIST: - tvs.actime = make_unix_date2(pdata+8); - tvs.modtime = make_unix_date2(pdata+12); - size = IVAL(pdata,16); - mode = IVAL(pdata,24); - break; - - /* XXXX nor this. not in cifs6.txt, either. */ - case SMB_INFO_QUERY_ALL_EAS: - tvs.actime = make_unix_date2(pdata+8); - tvs.modtime = make_unix_date2(pdata+12); - size = IVAL(pdata,16); - mode = IVAL(pdata,24); - break; - - case SMB_SET_FILE_BASIC_INFO: - case 1004: - { - /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */ - time_t write_time; - time_t changed_time; - - /* Ignore create time at offset pdata. */ - - /* access time */ - tvs.actime = interpret_long_date(pdata+8); - - write_time = interpret_long_date(pdata+16); - changed_time = interpret_long_date(pdata+24); - - tvs.modtime = MIN(write_time, changed_time); - - /* Prefer a defined time to an undefined one. */ - if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1) - tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1 - ? changed_time - : write_time); - - /* attributes */ - mode = IVAL(pdata,32); - break; - } + /* + * Only allow delete on close for writable shares. + */ - case SMB_FILE_ALLOCATION_INFORMATION: - case SMB_SET_FILE_ALLOCATION_INFO: - { - int ret = -1; - size = IVAL(pdata,0); + if (delete_on_close && !CAN_WRITE(fsp->conn)) { + DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; + } + /* + * Only allow delete on close for files/directories opened with delete intent. + */ + + if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) { + DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; + } + + if(fsp->is_directory) { + fsp->directory_delete_on_close = delete_on_close; + DEBUG(10, ("set_delete_on_close_internal: %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, ("set_delete_on_close_internal: %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,("set_delete_on_close_internal: %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 NT_STATUS_ACCESS_DENIED; + + if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) { + DEBUG(0,("set_delete_on_close_internal: failed to change delete on close flag for file %s\n", + fsp->fsp_name )); + unlock_share_entry_fsp(fsp); + return NT_STATUS_ACCESS_DENIED; + } + + /* + * 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, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n", + delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); + + } + + return NT_STATUS_OK; +} + +/**************************************************************************** + Returns true if this pathname is within the share, and thus safe. +****************************************************************************/ + +static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out) +{ +#ifdef PATH_MAX + char resolved_name[PATH_MAX+1]; +#else + pstring resolved_name; +#endif + pstring link_dest; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + + pstrcpy(link_dest, link_dest_in); + unix_convert(link_dest,conn,0,&bad_path,&sbuf); + + if (conn->vfs_ops.realpath(conn,dos_to_unix(link_dest,False),resolved_name) == NULL) + return -1; + + pstrcpy(link_dest, unix_to_dos(resolved_name,False)); + + if (*link_dest != '/') { + /* Relative path. */ + pstrcpy(link_dest_out, conn->connectpath); + pstrcat(link_dest_out, "/"); + pstrcat(link_dest_out, link_dest); + } else { + pstrcpy(link_dest_out, link_dest); + } + + /* + * Check if the link is within the share. + */ + + if (strncmp(conn->connectpath, link_dest_out, strlen(conn->connectpath))) { + errno = EACCES; + return -1; + } + return 0; +} + +/**************************************************************************** + Reply to a TRANS2_SETFILEINFO (set file info by fileid). +****************************************************************************/ + +static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) +{ + char *params = *pparams; + char *pdata = *ppdata; + uint16 tran_call = SVAL(inbuf, smb_setup0); + uint16 info_level; + int dosmode = 0; + SMB_OFF_T size=0; + struct utimbuf tvs; + SMB_STRUCT_STAT sbuf; + pstring fname1; + char *fname = NULL; + int fd = -1; + BOOL bad_path = False; + files_struct *fsp = NULL; + uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; + gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; + mode_t unixmode = 0; + + if (tran_call == TRANSACT2_SETFILEINFO) { + + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + fsp = file_fsp(params,0); + info_level = SVAL(params,2); + + if(fsp && (fsp->is_directory || fsp->stat_open)) { + /* + * This is actually a SETFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + fname = fsp->fsp_name; + unix_convert(fname,conn,0,&bad_path,&sbuf); + if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { + DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + } else if (fsp && fsp->print_file) { + /* + * Doing a DELETE_ON_CLOSE should cancel a print job. + */ + if (((info_level == SMB_SET_FILE_DISPOSITION_INFO)||(info_level == SMB_FILE_DISPOSITION_INFORMATION)) && + CVAL(pdata,0)) { + fsp->share_mode = FILE_DELETE_ON_CLOSE; + + DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", + fsp->fsp_name )); + + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); + } + } else { + /* + * Original code - this is an open file. + */ + CHECK_FSP(fsp,conn); + + fname = fsp->fsp_name; + fd = fsp->fd; + + if (vfs_fstat(fsp,fd,&sbuf) != 0) { + DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + return(UNIXERROR(ERRDOS,ERRbadfid)); + } + } + } else { + /* set path info */ + if (total_params < 6) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + info_level = SVAL(params,0); + fname = fname1; + pstrcpy(fname,¶ms[6]); + unix_convert(fname,conn,0,&bad_path,&sbuf); + if(!check_name(fname, conn)) { + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + + /* + * For CIFS UNIX extensions the target name may not exist. + */ + + if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) { + + DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + } + + if (!CAN_WRITE(conn)) + return ERROR_DOS(ERRSRV,ERRaccess); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) + return ERROR_DOS(ERRDOS,ERRunknownlevel); + + if (VALID_STAT(sbuf)) + unixmode = sbuf.st_mode; + + DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n", + tran_call,fname,info_level,total_data)); + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,2); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + SSVAL(params,0,0); + + size = sbuf.st_size; + tvs.modtime = sbuf.st_mtime; + tvs.actime = sbuf.st_atime; + dosmode = dos_mode(conn,fname,&sbuf); + unixmode = sbuf.st_mode; + + set_owner = VALID_STAT(sbuf) ? sbuf.st_uid : (uid_t)SMB_UID_NO_CHANGE; + set_grp = VALID_STAT(sbuf) ? sbuf.st_gid : (gid_t)SMB_GID_NO_CHANGE; + + if (total_data > 4 && IVAL(pdata,0) == total_data) { + /* uggh, EAs for OS2 */ + DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); + return ERROR_DOS(ERRDOS,ERReasnotsupported); + } + + switch (info_level) { + case SMB_INFO_STANDARD: + case SMB_INFO_QUERY_EA_SIZE: + { + if (total_data < l1_cbFile+4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + /* access time */ + tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess); + + /* write time */ + tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite); + + dosmode = SVAL(pdata,l1_attrFile); + size = IVAL(pdata,l1_cbFile); + break; + } + + /* XXXX um, i don't think this is right. + it's also not in the cifs6.txt spec. + */ + case SMB_INFO_QUERY_EAS_FROM_LIST: + if (total_data < 28) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + tvs.actime = make_unix_date2(pdata+8); + tvs.modtime = make_unix_date2(pdata+12); + size = IVAL(pdata,16); + dosmode = IVAL(pdata,24); + break; + + /* XXXX nor this. not in cifs6.txt, either. */ + case SMB_INFO_QUERY_ALL_EAS: + if (total_data < 28) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + tvs.actime = make_unix_date2(pdata+8); + tvs.modtime = make_unix_date2(pdata+12); + size = IVAL(pdata,16); + dosmode = IVAL(pdata,24); + break; + + case SMB_SET_FILE_BASIC_INFO: + case SMB_FILE_BASIC_INFORMATION: + { + /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */ + time_t write_time; + time_t changed_time; + + if (total_data < 36) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + /* Ignore create time at offset pdata. */ + + /* access time */ + tvs.actime = interpret_long_date(pdata+8); + + write_time = interpret_long_date(pdata+16); + changed_time = interpret_long_date(pdata+24); + + tvs.modtime = MIN(write_time, changed_time); + + /* Prefer a defined time to an undefined one. */ + if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1) + tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1 + ? changed_time + : write_time); + + /* attributes */ + dosmode = IVAL(pdata,32); + break; + } + + case SMB_FILE_ALLOCATION_INFORMATION: + case SMB_SET_FILE_ALLOCATION_INFO: + { + int ret = -1; + SMB_OFF_T allocation_size; + + if (total_data < 8) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + allocation_size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T - size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); + allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ - if (IVAL(pdata,4) != 0) /* more than 32 bits? */ - return(ERROR(ERRDOS,ERRunknownlevel)); + if (IVAL(pdata,4) != 0) /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); #endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", - fname, (double)size )); + DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", + fname, (double)allocation_size )); - if(size != sbuf.st_size) { + if(allocation_size != sbuf.st_size) { + SMB_STRUCT_STAT new_sbuf; - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n", - fname, (double)size )); + DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new allocation size to %.0f\n", + fname, (double)allocation_size )); - if (fd == -1) { - files_struct *new_fsp = NULL; - int access_mode = 0; - int action = 0; + if (fd == -1) { + files_struct *new_fsp = NULL; + int access_mode = 0; + int action = 0; - if(global_oplock_break) { - /* Queue this file modify as we are the process of an oplock break. */ + if(global_oplock_break) { + /* Queue this file modify as we are the process of an oplock break. */ - DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being ")); - DEBUGADD(2,( "in oplock break state.\n")); + DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being ")); + DEBUGADD(2,( "in oplock break state.\n")); - push_oplock_pending_smb_message(inbuf, length); - return -1; - } + push_oplock_pending_smb_message(inbuf, length); + return -1; + } + + new_fsp = open_file_shared(conn, fname, &sbuf, + SET_OPEN_MODE(DOS_OPEN_RDWR), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + 0, 0, &access_mode, &action); - new_fsp = open_file_shared(conn, fname, &sbuf, - SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - 0, 0, &access_mode, &action); - - if (new_fsp == NULL) - return(UNIXERROR(ERRDOS,ERRbadpath)); - ret = vfs_allocate_file_space(new_fsp, size); - close_file(new_fsp,True); - } else { - ret = vfs_allocate_file_space(fsp, size); - } - if (ret == -1) - return allocate_space_error(inbuf, outbuf, errno); - - sbuf.st_size = size; - } - - break; - } + if (new_fsp == NULL) + return(UNIXERROR(ERRDOS,ERRbadpath)); + ret = vfs_allocate_file_space(new_fsp, allocation_size); + if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) { + DEBUG(3,("fstat of fnum %d failed (%s)\n",new_fsp->fnum, strerror(errno))); + ret = -1; + } + close_file(new_fsp,True); + } else { + ret = vfs_allocate_file_space(fsp, allocation_size); + if (vfs_fstat(fsp,fd,&new_sbuf) != 0) { + DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + ret = -1; + } + } + if (ret == -1) + return ERROR_NT(NT_STATUS_DISK_FULL); - case SMB_FILE_END_OF_FILE_INFORMATION: - case SMB_SET_FILE_END_OF_FILE_INFO: - { - size = IVAL(pdata,0); + /* Allocate can trucate size... */ + size = new_sbuf.st_size; + } + + break; + } + + case SMB_FILE_END_OF_FILE_INFORMATION: + case SMB_SET_FILE_END_OF_FILE_INFO: + { + if (total_data < 8) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T - size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); + size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ - if (IVAL(pdata,4) != 0) /* more than 32 bits? */ - return(ERROR(ERRDOS,ERRunknownlevel)); + if (IVAL(pdata,4) != 0) /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); #endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size )); - break; - } + DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size )); + break; + } - case SMB_FILE_DISPOSITION_INFORMATION: - case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */ - { - BOOL delete_on_close = (CVAL(pdata,0) ? True : False); + case SMB_FILE_DISPOSITION_INFORMATION: + case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */ + { + BOOL delete_on_close; + NTSTATUS status; - if (tran_call != TRANSACT2_SETFILEINFO) - return(ERROR(ERRDOS,ERRunknownlevel)); + if (total_data < 1) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - if (fsp == NULL) - return(UNIXERROR(ERRDOS,ERRbadfid)); + delete_on_close = (CVAL(pdata,0) ? True : False); - /* - * Only allow delete on close for files/directories opened with delete intent. - */ + if (tran_call != TRANSACT2_SETFILEINFO) + return(ERROR_DOS(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 == NULL) + return(UNIXERROR(ERRDOS,ERRbadfid)); - 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) { + status = set_delete_on_close_internal(fsp, delete_on_close); - 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 )); + if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) + return ERROR_NT(status); - } else { + break; + } - files_struct *iterate_fsp; + /* + * CIFS UNIX extensions. + */ - /* - * 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. - */ + case SMB_SET_FILE_UNIX_BASIC: + { + uint32 raw_unixmode; - 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 (total_data < 100) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - if (lock_share_entry_fsp(fsp) == False) - return(ERROR(ERRDOS,ERRnoaccess)); + size=IVAL(pdata,0); /* first 8 Bytes are size */ +#ifdef LARGE_SMB_OFF_T + size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); +#else /* LARGE_SMB_OFF_T */ + if (IVAL(pdata,4) != 0) /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); +#endif /* LARGE_SMB_OFF_T */ + pdata+=24; /* ctime & st_blocks are not changed */ + tvs.actime = interpret_long_date(pdata); /* access_time */ + tvs.modtime = interpret_long_date(pdata+8); /* modification_time */ + pdata+=16; + set_owner = (uid_t)IVAL(pdata,0); + pdata += 8; + set_grp = (gid_t)IVAL(pdata,0); + pdata += 8; + raw_unixmode = IVAL(pdata,28); + unixmode = unix_perms_from_wire(conn, &sbuf, raw_unixmode); + dosmode = 0; /* Ensure dos mode change doesn't override this. */ + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC: name = %s \ +size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", + fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode)); + + if (!VALID_STAT(sbuf)) { + + /* + * The only valid use of this is to create character and block + * devices, and named pipes. This is deprecated (IMHO) and + * a new info level should be used for mknod. JRA. + */ + +#if !defined(HAVE_MAKEDEV_FN) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); +#else /* HAVE_MAKEDEV_FN */ + uint32 file_type = IVAL(pdata,0); + uint32 dev_major = IVAL(pdata,4); + uint32 dev_minor = IVAL(pdata,12); + + uid_t myuid = geteuid(); + gid_t mygid = getegid(); + SMB_DEV_T dev; + + if (tran_call == TRANSACT2_SETFILEINFO) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + if (raw_unixmode == SMB_MODE_NO_CHANGE) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + dev = makedev(dev_major, dev_minor); + + /* We can only create as the owner/group we are. */ + + if ((set_owner != myuid) && (set_owner != (uid_t)SMB_UID_NO_CHANGE)) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + if ((set_grp != mygid) && (set_grp != (gid_t)SMB_GID_NO_CHANGE)) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV && + file_type != UNIX_TYPE_FIFO) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ +0%o for file %s\n", (double)dev, unixmode, fname )); + + /* Ok - do the mknod. */ + if (conn->vfs_ops.mknod(conn,dos_to_unix(fname,False), unixmode, dev) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); +#endif /* HAVE_MAKEDEV_FN */ - 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. + * Deal with the UNIX specific mode set. */ - unlock_share_entry_fsp(fsp); + if (raw_unixmode != SMB_MODE_NO_CHANGE) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", + unixmode, fname )); + if (vfs_chmod(conn,fname,unixmode) != 0) + return(UNIXERROR(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. - * 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. + * Deal with the UNIX specific uid set. */ - 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; + if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n", + (unsigned int)set_owner, fname )); + if (vfs_chown(conn,fname,set_owner, (gid_t)-1) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } /* - * Set the delete on close flag in the fsp. + * Deal with the UNIX specific gid set. */ - 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 )); + if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n", + (unsigned int)set_owner, fname )); + if (vfs_chown(conn,fname,(uid_t)-1, set_grp) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + break; + } + + case SMB_SET_FILE_UNIX_LINK: + { + pstring link_dest; + /* Set a symbolic link. */ + /* Don't allow this if follow links is false. */ + + if (!lp_symlinks(SNUM(conn))) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + /* Disallow if already exists. */ + if (VALID_STAT(sbuf)) + return(ERROR_DOS(ERRDOS,ERRbadpath)); + + pstrcpy(link_dest, pdata); + + if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + dos_to_unix(link_dest, True); + dos_to_unix(fname, True); + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", + fname, link_dest )); + + if (conn->vfs_ops.symlink(conn,link_dest,fname) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); } - break; + case SMB_SET_FILE_UNIX_HLINK: + { + pstring link_dest; + + /* Set a hard link. */ + + /* Disallow if already exists. */ + if (VALID_STAT(sbuf)) + return(ERROR_DOS(ERRDOS,ERRbadpath)); + + pstrcpy(link_dest, pdata); + + if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + + dos_to_unix(link_dest, True); + dos_to_unix(fname, True); + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", + fname, link_dest )); + + if (conn->vfs_ops.link(conn,link_dest,fname) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); + } + + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); } - default: - { - return(ERROR(ERRDOS,ERRunknownlevel)); + /* get some defaults (no modifications) if any info is zero or -1. */ + if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1) + tvs.actime = sbuf.st_atime; + + if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1) + tvs.modtime = sbuf.st_mtime; + + DEBUG(6,("actime: %s " , ctime(&tvs.actime))); + DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); + DEBUG(6,("size: %.0f ", (double)size)); + DEBUG(6,("dosmode: %x\n" , dosmode)); + + if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) || + (info_level == SMB_SET_FILE_ALLOCATION_INFO) || + (info_level == SMB_FILE_ALLOCATION_INFORMATION) || + (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) { + /* + * Only do this test if we are not explicitly + * changing the size of a file. + */ + if (!size) + size = sbuf.st_size; } - } - - /* get some defaults (no modifications) if any info is zero or -1. */ - if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1) - tvs.actime = sbuf.st_atime; - - if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1) - tvs.modtime = sbuf.st_mtime; - - DEBUG(6,("actime: %s " , ctime(&tvs.actime))); - DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); - DEBUG(6,("size: %.0f ", (double)size)); - DEBUG(6,("mode: %x\n" , mode)); - - if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) || - (info_level == SMB_SET_FILE_ALLOCATION_INFO) || - (info_level == 1019) || - (info_level == 1020))) { - /* - * Only do this test if we are not explicitly - * changing the size of a file. - */ - if (!size) - size = sbuf.st_size; - } - - /* Try and set the times, size and mode of this file - - if they are different from the current values - */ - if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) { - if(fsp != NULL) { - /* - * This was a setfileinfo on an open file. - * NT does this a lot. It's actually pointless - * setting the time here, as it will be overwritten - * on the next write, so we save the request - * away and will set it on file code. JRA. - */ - - if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { - DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", - ctime(&tvs.modtime) )); - fsp->pending_modtime = tvs.modtime; - } - - } else { - - DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n")); - - if(file_utime(conn, fname, &tvs)!=0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - } - - /* check the mode isn't different, before changing it */ - if ((mode != 0) && (mode != dos_mode(conn, fname, &sbuf))) { - - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", - fname, mode )); - - if(file_chmod(conn, fname, mode, NULL)) { - DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno))); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - } - - if(size != sbuf.st_size) { - - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n", - fname, (double)size )); - - if (fd == -1) { - files_struct *new_fsp = NULL; - int access_mode = 0; - int action = 0; - - if(global_oplock_break) { - /* Queue this file modify as we are the process of an oplock break. */ - - DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being ")); - DEBUGADD(2,( "in oplock break state.\n")); - - push_oplock_pending_smb_message(inbuf, length); - return -1; - } - - new_fsp = open_file_shared(conn, fname, &sbuf, - SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - 0, 0, &access_mode, &action); + + /* + * Try and set the times, size and mode of this file - + * if they are different from the current values + */ + + if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) { + if(fsp != NULL) { + /* + * This was a setfileinfo on an open file. + * NT does this a lot. It's actually pointless + * setting the time here, as it will be overwritten + * on the next write, so we save the request + * away and will set it on file code. JRA. + */ + + if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { + DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", + ctime(&tvs.modtime) )); + fsp->pending_modtime = tvs.modtime; + } + + } else { + + DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n")); + + if(file_utime(conn, fname, &tvs)!=0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + } + + /* check the mode isn't different, before changing it */ + if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) { + + DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", + fname, dosmode )); + + if(file_chmod(conn, fname, dosmode, NULL)) { + DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno))); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + } + + if(size != sbuf.st_size) { + + DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n", + fname, (double)size )); + + if (fd == -1) { + files_struct *new_fsp = NULL; + int access_mode = 0; + int action = 0; + + if(global_oplock_break) { + /* Queue this file modify as we are the process of an oplock break. */ + + DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being ")); + DEBUGADD(2,( "in oplock break state.\n")); + + push_oplock_pending_smb_message(inbuf, length); + return -1; + } + + new_fsp = open_file_shared(conn, fname, &sbuf, + SET_OPEN_MODE(DOS_OPEN_RDWR), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + 0, 0, &access_mode, &action); - if (new_fsp == NULL) - return(UNIXERROR(ERRDOS,ERRbadpath)); - vfs_set_filelen(new_fsp, size); - close_file(new_fsp,True); - } else { - vfs_set_filelen(fsp, size); - } - } - - SSVAL(params,0,0); - - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - - return(-1); + if (new_fsp == NULL) + return(UNIXERROR(ERRDOS,ERRbadpath)); + vfs_set_filelen(new_fsp, size); + close_file(new_fsp,True); + } else { + vfs_set_filelen(fsp, size); + } + } + + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); } /**************************************************************************** - reply to a TRANS2_MKDIR (make directory with extended attributes). + Reply to a TRANS2_MKDIR (make directory with extended attributes). ****************************************************************************/ -static int call_trans2mkdir(connection_struct *conn, - char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, char **ppdata) + +static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; - pstring directory; - int ret = -1; - SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; + char *params = *pparams; + pstring directory; + int ret = -1; + SMB_STRUCT_STAT sbuf; + BOOL bad_path = False; + + if (!CAN_WRITE(conn)) + return ERROR_DOS(ERRSRV,ERRaccess); - if (!CAN_WRITE(conn)) - return(ERROR(ERRSRV,ERRaccess)); + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - pstrcpy(directory, ¶ms[4]); + pstrcpy(directory, ¶ms[4]); - DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); + DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (check_name(directory,conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + unix_convert(directory,conn,0,&bad_path,&sbuf); + if (check_name(directory,conn)) + ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); - if(ret < 0) - { - DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,2); - if(params == NULL) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; - - SSVAL(params,0,0); - - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + if(ret < 0) { + DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,2); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + SSVAL(params,0,0); + + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** - reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes) - We don't actually do this - we just send a null response. + Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes). + We don't actually do this - we just send a null response. ****************************************************************************/ -static int call_trans2findnotifyfirst(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) + +static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - static uint16 fnf_handle = 257; - char *params = *pparams; - uint16 info_level = SVAL(params,4); - - DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); - - switch (info_level) - { - case 1: - case 2: - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,6); - if(params == NULL) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; - - SSVAL(params,0,fnf_handle); - SSVAL(params,2,0); /* No changes */ - SSVAL(params,4,0); /* No EA errors */ - - fnf_handle++; - - if(fnf_handle == 0) - fnf_handle = 257; - - send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); + static uint16 fnf_handle = 257; + char *params = *pparams; + uint16 info_level; + + if (total_params < 6) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + info_level = SVAL(params,4); + DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); + + switch (info_level) { + case 1: + case 2: + break; + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,6); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + SSVAL(params,0,fnf_handle); + SSVAL(params,2,0); /* No changes */ + SSVAL(params,4,0); /* No EA errors */ + + fnf_handle++; + + if(fnf_handle == 0) + fnf_handle = 257; + + send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** - reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for - changes). Currently this does nothing. + Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for + changes). Currently this does nothing. ****************************************************************************/ -static int call_trans2findnotifynext(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) + +static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; + char *params = *pparams; - DEBUG(3,("call_trans2findnotifynext\n")); + DEBUG(3,("call_trans2findnotifynext\n")); - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,4); - if(params == NULL) { - return(ERROR(ERRDOS,ERRnomem)); - } - *pparams = params; + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,4); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; - SSVAL(params,0,0); /* No changes */ - SSVAL(params,2,0); /* No EA errors */ + SSVAL(params,0,0); /* No changes */ + SSVAL(params,2,0); /* No EA errors */ - send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** - reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com> + Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>. ****************************************************************************/ -static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, - char* outbuf, int length, int bufsize, - char** pparams, char** ppdata) + +static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; - enum remote_arch_types ra_type = get_remote_arch(); - BOOL NT_arch = ((ra_type == RA_WINNT) || (ra_type == RA_WIN2K)); - pstring pathname; - int reply_size = 0; - int max_referral_level = SVAL(params,0); - - - DEBUG(10,("call_trans2getdfsreferral\n")); - - if(!lp_host_msdfs()) - return(ERROR(ERRDOS,ERRbadfunc)); - - /* if pathname is in UNICODE, convert to DOS */ - /* NT always sends in UNICODE, may not set UNICODE flag */ - if(NT_arch || (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS)) - { - unistr_to_dos(pathname, ¶ms[2], sizeof(pathname)); - DEBUG(10,("UNICODE referral for %s\n",pathname)); - } - else - pstrcpy(pathname,¶ms[2]); - - if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0) - return(ERROR(ERRDOS,ERRbadfile)); + char *params = *pparams; + enum remote_arch_types ra_type = get_remote_arch(); + BOOL NT_arch = ((ra_type == RA_WINNT) || (ra_type == RA_WIN2K)); + pstring pathname; + int reply_size = 0; + int max_referral_level; + + DEBUG(10,("call_trans2getdfsreferral\n")); + + if (total_params < 2) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + max_referral_level = SVAL(params,0); + + if(!lp_host_msdfs()) + return ERROR_DOS(ERRDOS,ERRbadfunc); + + /* if pathname is in UNICODE, convert to DOS */ + /* NT always sends in UNICODE, may not set UNICODE flag */ + if(NT_arch || (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS)) { + unistr_to_dos(pathname, ¶ms[2], sizeof(pathname)); + DEBUG(10,("UNICODE referral for %s\n",pathname)); + } else + pstrcpy(pathname,¶ms[2]); + + if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0) + return ERROR_DOS(ERRDOS,ERRbadfile); - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_UNICODE_STRINGS | - FLAGS2_DFS_PATHNAMES); - send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_UNICODE_STRINGS | FLAGS2_DFS_PATHNAMES); + send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); - return(-1); + return(-1); } #define LMCAT_SPL 0x53 @@ -2347,38 +2992,35 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, reply to a TRANS2_IOCTL - used for OS/2 printing. ****************************************************************************/ -static int call_trans2ioctl(connection_struct *conn, char* inbuf, - char* outbuf, int length, int bufsize, - char** pparams, char** ppdata) +static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *pdata = *ppdata; - files_struct *fsp = file_fsp(inbuf,smb_vwv15); - - if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && - (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { - pdata = Realloc(*ppdata, 32); - if(pdata == NULL) { - return(ERROR(ERRDOS,ERRnomem)); - } - *ppdata = pdata; - - SSVAL(pdata,0,fsp->print_jobid); /* Job number */ - StrnCpy(pdata+2, global_myname, 15); /* Our NetBIOS name */ - StrnCpy(pdata+18, lp_servicename(SNUM(conn)), 13); /* Service name */ - send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); - return(-1); - } else { - DEBUG(2,("Unknown TRANS2_IOCTL\n")); - return(ERROR(ERRSRV,ERRerror)); - } + char *pdata = *ppdata; + files_struct *fsp = file_fsp(inbuf,smb_vwv15); + + if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && + (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + pdata = Realloc(*ppdata, 32); + if(pdata == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *ppdata = pdata; + + SSVAL(pdata,0,fsp->print_jobid); /* Job number */ + StrnCpy(pdata+2, global_myname, 15); /* Our NetBIOS name */ + StrnCpy(pdata+18, lp_servicename(SNUM(conn)), 13); /* Service name */ + send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); + return(-1); + } else { + DEBUG(2,("Unknown TRANS2_IOCTL\n")); + return ERROR_DOS(ERRSRV,ERRerror); + } } /**************************************************************************** Reply to a SMBfindclose (stop trans2 directory search). ****************************************************************************/ -int reply_findclose(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) +int reply_findclose(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { int outsize = 0; int dptr_num=SVALS(inbuf,smb_vwv0); @@ -2400,8 +3042,7 @@ int reply_findclose(connection_struct *conn, Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search). ****************************************************************************/ -int reply_findnclose(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) +int reply_findnclose(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { int outsize = 0; int dptr_num= -1; @@ -2427,8 +3068,7 @@ int reply_findnclose(connection_struct *conn, Reply to a SMBtranss2 - just ignore it! ****************************************************************************/ -int reply_transs2(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) +int reply_transs2(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { START_PROFILE(SMBtranss2); DEBUG(4,("Ignoring transs2 of length %d\n",length)); @@ -2437,10 +3077,10 @@ int reply_transs2(connection_struct *conn, } /**************************************************************************** - reply to a SMBtrans2 + Reply to a SMBtrans2. ****************************************************************************/ -int reply_trans2(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) + +int reply_trans2(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { int outsize = 0; unsigned int total_params = SVAL(inbuf, smb_tpscnt); @@ -2474,7 +3114,7 @@ int reply_trans2(connection_struct *conn, if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN) && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) { END_PROFILE(SMBtrans2); - return(ERROR(ERRSRV,ERRaccess)); + return ERROR_DOS(ERRSRV,ERRaccess); } outsize = set_message(outbuf,0,0,True); @@ -2498,7 +3138,7 @@ int reply_trans2(connection_struct *conn, DEBUG(2,("Invalid smb_sucnt in trans2 call(%d)\n",suwcnt)); DEBUG(2,("Transaction is %d\n",tran_call)); END_PROFILE(SMBtrans2); - return(ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } } @@ -2510,12 +3150,10 @@ int reply_trans2(connection_struct *conn, if ((total_params && !params) || (total_data && !data)) { DEBUG(2,("Out of memory in reply_trans2\n")); - if(params) - free(params); - if(data) - free(data); + SAFE_FREE(params); + SAFE_FREE(data); END_PROFILE(SMBtrans2); - return(ERROR(ERRDOS,ERRnomem)); + return ERROR_DOS(ERRDOS,ERRnomem); } /* Copy the param and data bytes sent with this request into @@ -2536,7 +3174,7 @@ int reply_trans2(connection_struct *conn, of the parameter/data bytes */ outsize = set_message(outbuf,0,0,True); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_trans2: send_smb failed.\n"); + exit_server("reply_trans2: send_smb failed."); while (num_data_sofar < total_data || num_params_sofar < total_params) { @@ -2552,12 +3190,10 @@ int reply_trans2(connection_struct *conn, else DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n", (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - if(params) - free(params); - if(data) - free(data); + SAFE_FREE(params); + SAFE_FREE(data); END_PROFILE(SMBtrans2); - return(ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } /* Revise total_params and total_data in case @@ -2577,112 +3213,100 @@ int reply_trans2(connection_struct *conn, } if (Protocol >= PROTOCOL_NT1) { - uint16 flg2 = SVAL(outbuf,smb_flg2); - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */ } /* Now we must call the relevant TRANS2 function */ switch(tran_call) { case TRANSACT2_OPEN: START_PROFILE_NESTED(Trans2_open); - outsize = call_trans2open(conn, - inbuf, outbuf, bufsize, - ¶ms, &data); + outsize = call_trans2open(conn, inbuf, outbuf, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_open); break; case TRANSACT2_FINDFIRST: START_PROFILE_NESTED(Trans2_findfirst); - outsize = call_trans2findfirst(conn, inbuf, outbuf, - bufsize, ¶ms, &data); + outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findfirst); break; case TRANSACT2_FINDNEXT: START_PROFILE_NESTED(Trans2_findnext); - outsize = call_trans2findnext(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findnext); break; case TRANSACT2_QFSINFO: START_PROFILE_NESTED(Trans2_qfsinfo); - outsize = call_trans2qfsinfo(conn, inbuf, outbuf, - length, bufsize, ¶ms, - &data); + outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_qfsinfo); break; case TRANSACT2_SETFSINFO: START_PROFILE_NESTED(Trans2_setfsinfo); - outsize = call_trans2setfsinfo(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_setfsinfo); break; case TRANSACT2_QPATHINFO: case TRANSACT2_QFILEINFO: START_PROFILE_NESTED(Trans2_qpathinfo); - outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data, total_data); + outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_qpathinfo); break; case TRANSACT2_SETPATHINFO: case TRANSACT2_SETFILEINFO: START_PROFILE_NESTED(Trans2_setpathinfo); - outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data, - total_data); + outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_setpathinfo); break; case TRANSACT2_FINDNOTIFYFIRST: START_PROFILE_NESTED(Trans2_findnotifyfirst); - outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findnotifyfirst); break; case TRANSACT2_FINDNOTIFYNEXT: START_PROFILE_NESTED(Trans2_findnotifynext); - outsize = call_trans2findnotifynext(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findnotifynext); break; case TRANSACT2_MKDIR: START_PROFILE_NESTED(Trans2_mkdir); - outsize = call_trans2mkdir(conn, inbuf, outbuf, length, - bufsize, ¶ms, &data); + outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_mkdir); break; case TRANSACT2_GET_DFS_REFERRAL: START_PROFILE_NESTED(Trans2_get_dfs_referral); - outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, - bufsize, ¶ms, &data); + outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_get_dfs_referral); break; case TRANSACT2_IOCTL: START_PROFILE_NESTED(Trans2_ioctl); - outsize = call_trans2ioctl(conn,inbuf,outbuf,length, - bufsize,¶ms,&data); + outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_ioctl); break; default: /* Error in request */ DEBUG(2,("Unknown request %d in trans2 call\n", tran_call)); - if(params) - free(params); - if(data) - free(data); + SAFE_FREE(params); + SAFE_FREE(data); END_PROFILE(SMBtrans2); - return (ERROR(ERRSRV,ERRerror)); + return ERROR_DOS(ERRSRV,ERRerror); } /* As we do not know how many data packets will need to be @@ -2692,10 +3316,8 @@ int reply_trans2(connection_struct *conn, an error packet. */ - if(params) - free(params); - if(data) - free(data); + SAFE_FREE(params); + SAFE_FREE(data); END_PROFILE(SMBtrans2); return outsize; /* If a correct response was needed the call_trans2xxx calls have already sent diff --git a/source/smbd/uid.c b/source/smbd/uid.c index 54ced5a8239..5204f36ad6e 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -21,16 +21,14 @@ #include "includes.h" -extern int DEBUGLEVEL; - /* what user is current? */ extern struct current_user current_user; /**************************************************************************** - Become the guest user. + Become the guest user without changing the security context stack. ****************************************************************************/ -BOOL become_guest(void) +BOOL change_to_guest(void) { static struct passwd *pass=NULL; static uid_t guest_uid = (uid_t)-1; @@ -84,10 +82,11 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) } /**************************************************************************** - Become the user of a connection number. + Become the user of a connection number without changing the security context + stack, but modify the currnet_user entries. ****************************************************************************/ -BOOL become_user(connection_struct *conn, uint16 vuid) +BOOL change_to_user(connection_struct *conn, uint16 vuid) { user_struct *vuser = get_valid_user_struct(vuid); int snum; @@ -98,7 +97,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid) NT_USER_TOKEN *token = NULL; if (!conn) { - DEBUG(2,("Connection not open\n")); + DEBUG(2,("change_to_user: Connection not open\n")); return(False); } @@ -111,12 +110,12 @@ BOOL become_user(connection_struct *conn, uint16 vuid) if((lp_security() == SEC_SHARE) && (current_user.conn == conn) && (current_user.uid == conn->uid)) { - DEBUG(4,("Skipping become_user - already user\n")); + DEBUG(4,("change_to_user: Skipping user change - already user\n")); return(True); } else if ((current_user.conn == conn) && (vuser != 0) && (current_user.vuid == vuid) && (current_user.uid == vuser->uid)) { - DEBUG(4,("Skipping become_user - already user\n")); + DEBUG(4,("change_to_user: Skipping user change - already user\n")); return(True); } @@ -135,7 +134,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid) token = conn->nt_user_token; } else { if (!vuser) { - DEBUG(2,("Invalid vuid used %d\n",vuid)); + DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid)); return(False); } uid = vuser->uid; @@ -182,7 +181,7 @@ BOOL become_user(connection_struct *conn, uint16 vuid) if (vuser && vuser->guest) is_guest = True; - token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest); + token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL); must_free_token = True; } @@ -198,21 +197,22 @@ BOOL become_user(connection_struct *conn, uint16 vuid) current_user.conn = conn; current_user.vuid = vuid; - DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n", + DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n", (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); return(True); } /**************************************************************************** - Unbecome the user of a connection number. + Go back to being root without changing the security context stack, + but modify the current_user entries. ****************************************************************************/ -BOOL unbecome_user(void ) +BOOL change_to_root_user(void) { set_root_sec_ctx(); - DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", + DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n", (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); current_user.conn = NULL; @@ -224,16 +224,13 @@ BOOL unbecome_user(void ) /**************************************************************************** Become the user of an authenticated connected named pipe. When this is called we are currently running as the connection - user. + user. Doesn't modify current_user. ****************************************************************************/ BOOL become_authenticated_pipe_user(pipes_struct *p) { - BOOL res = push_sec_ctx(); - - if (!res) { + if (!push_sec_ctx()) return False; - } set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid, p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token); @@ -244,19 +241,93 @@ BOOL become_authenticated_pipe_user(pipes_struct *p) /**************************************************************************** Unbecome the user of an authenticated connected named pipe. When this is called we are running as the authenticated pipe - user and need to go back to being the connection user. + user and need to go back to being the connection user. Doesn't modify + current_user. ****************************************************************************/ -BOOL unbecome_authenticated_pipe_user(pipes_struct *p) +BOOL unbecome_authenticated_pipe_user(void) { return pop_sec_ctx(); } -/* Temporarily become a root user. Must match with unbecome_root(). */ +/**************************************************************************** + Utility functions used by become_xxx/unbecome_xxx. +****************************************************************************/ + +struct conn_ctx { + connection_struct *conn; + uint16 vuid; +}; + +/* A stack of current_user connection contexts. */ + +static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH]; +static int conn_ctx_stack_ndx; + +static void push_conn_ctx(void) +{ + struct conn_ctx *ctx_p; + + /* Check we don't overflow our stack */ + + if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) { + DEBUG(0, ("Connection context stack overflow!\n")); + smb_panic("Connection context stack overflow!\n"); + } + + /* Store previous user context */ + ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx]; + + ctx_p->conn = current_user.conn; + ctx_p->vuid = current_user.vuid; + + DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n", + (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx )); + + conn_ctx_stack_ndx++; +} + +static void pop_conn_ctx(void) +{ + struct conn_ctx *ctx_p; + + /* Check for stack underflow. */ + + if (conn_ctx_stack_ndx == 0) { + DEBUG(0, ("Connection context stack underflow!\n")); + smb_panic("Connection context stack underflow!\n"); + } + + conn_ctx_stack_ndx--; + ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx]; + + current_user.conn = ctx_p->conn; + current_user.vuid = ctx_p->vuid; + + ctx_p->conn = NULL; + ctx_p->vuid = UID_FIELD_INVALID; +} + +void init_conn_ctx(void) +{ + int i; + + /* Initialise connection context stack */ + for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) { + conn_ctx_stack[i].conn = NULL; + conn_ctx_stack[i].vuid = UID_FIELD_INVALID; + } +} + +/**************************************************************************** + Temporarily become a root user. Must match with unbecome_root(). Saves and + restores the connection context. +****************************************************************************/ void become_root(void) { push_sec_ctx(); + push_conn_ctx(); set_root_sec_ctx(); } @@ -265,6 +336,104 @@ void become_root(void) void unbecome_root(void) { pop_sec_ctx(); + pop_conn_ctx(); +} + +/**************************************************************************** + Push the current security context then force a change via change_to_user(). + Saves and restores the connection context. +****************************************************************************/ + +BOOL become_user(connection_struct *conn, uint16 vuid) +{ + if (!push_sec_ctx()) + return False; + + push_conn_ctx(); + + if (!change_to_user(conn, vuid)) { + pop_sec_ctx(); + pop_conn_ctx(); + return False; + } + + return True; +} + +BOOL unbecome_user(void) +{ + pop_sec_ctx(); + pop_conn_ctx(); + return True; +} + +/***************************************************************** + Convert the suplimentary SIDs returned in a netlogon into UNIX + group gid_t's. Add to the total group array. +*****************************************************************/ + +void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER_TOKEN **pptok) +{ + int total_groups; + int current_n_groups = *n_groups; + gid_t *final_groups = NULL; + size_t i; + NT_USER_TOKEN *ptok = *pptok; + NT_USER_TOKEN *new_tok = NULL; + + if (!ptok || (ptok->num_sids == 0)) + return; + + new_tok = dup_nt_token(ptok); + if (!new_tok) { + DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new token\n")); + return; + } + /* Leave the allocated space but empty the number of SIDs. */ + new_tok->num_sids = 0; + + total_groups = current_n_groups + ptok->num_sids; + + final_groups = (gid_t *)malloc(total_groups * sizeof(gid_t)); + if (!final_groups) { + DEBUG(0,("add_supplementary_nt_login_groups: Failed to malloc new groups.\n")); + delete_nt_token(&new_tok); + return; + } + + memcpy(final_groups, *pp_groups, current_n_groups * sizeof(gid_t)); + for (i = 0; i < ptok->num_sids; i++) { + enum SID_NAME_USE sid_type; + gid_t new_grp; + + if (sid_to_gid(&ptok->user_sids[i], &new_grp, &sid_type)) { + /* + * Don't add the gid_t if it is already in the current group + * list. Some UNIXen don't like the same group more than once. + */ + int j; + + for (j = 0; j < current_n_groups; j++) + if (final_groups[j] == new_grp) + break; + + if ( j == current_n_groups) { + /* Group not already present. */ + final_groups[current_n_groups++] = new_grp; + } + } else { + /* SID didn't map. Copy to the new token to be saved. */ + sid_copy(&new_tok->user_sids[new_tok->num_sids++], &ptok->user_sids[i]); + } + } + + SAFE_FREE(*pp_groups); + *pp_groups = final_groups; + *n_groups = current_n_groups; + + /* Replace the old token with the truncated one. */ + delete_nt_token(&ptok); + *pptok = new_tok; } /***************************************************************** @@ -282,7 +451,7 @@ BOOL lookup_name(const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type) *name_type = SID_NAME_UNKNOWN; if (!winbind_lookup_name(name, psid, name_type) || (*name_type != SID_NAME_USER) ) { - BOOL ret; + BOOL ret = False; DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name)); @@ -382,16 +551,22 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid) { + uid_t low, high; fstring sid; - if (!winbind_uid_to_sid(psid, uid)) { - DEBUG(10,("uid_to_sid: winbind lookup for uid %u failed - trying local.\n", (unsigned int)uid )); + if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) { + if (winbind_uid_to_sid(psid, uid)) { - return local_uid_to_sid(psid, uid); + DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", + (unsigned int)uid, sid_to_string(sid, psid))); + + return psid; + } } - DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", - (unsigned int)uid, sid_to_string(sid, psid) )); + local_uid_to_sid(psid, uid); + + DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid))); return psid; } @@ -404,16 +579,22 @@ DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid) DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid) { + gid_t low, high; fstring sid; - if (!winbind_gid_to_sid(psid, gid)) { - DEBUG(10,("gid_to_sid: winbind lookup for gid %u failed - trying local.\n", (unsigned int)gid )); + if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) { + if (winbind_gid_to_sid(psid, gid)) { - return local_gid_to_sid(psid, gid); + DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", + (unsigned int)gid, sid_to_string(sid, psid))); + + return psid; + } } - DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", - (unsigned int)gid, sid_to_string(sid,psid) )); + local_gid_to_sid(psid, gid); + + DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid))); return psid; } @@ -520,7 +701,7 @@ BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype) return False; } - DEBUG(10,("gid_to_uid: winbindd %s -> %u\n", + DEBUG(10,("sid_to_gid: winbindd %s -> %u\n", sid_to_string(sid_str, psid), (unsigned int)*pgid )); diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c index f79cd43c5b1..92e001cd036 100644 --- a/source/smbd/utmp.c +++ b/source/smbd/utmp.c @@ -127,7 +127,7 @@ Notes: #endif /**************************************************************************** -obtain/release a small number (0 upwards) unique within and across smbds + Obtain/release a small number (0 upwards) unique within and across smbds. ****************************************************************************/ /* * Need a "small" number to represent this connection, unique within this @@ -154,8 +154,9 @@ obtain/release a small number (0 upwards) unique within and across smbds */ /**************************************************************************** -Default paths to various {u,w}tmp{,x} files + Default paths to various {u,w}tmp{,x} files. ****************************************************************************/ + #ifdef HAVE_UTMPX_H static const char *ux_pathname = @@ -260,9 +261,11 @@ static void uw_pathname(pstring fname, const char *uw_name, const char *uw_defau } #ifndef HAVE_PUTUTLINE + /**************************************************************************** -Update utmp file directly. No subroutine interface: probably a BSD system. + Update utmp file directly. No subroutine interface: probably a BSD system. ****************************************************************************/ + static void pututline_my(pstring uname, struct utmp *u, BOOL claim) { DEBUG(1,("pututline_my: not yet implemented\n")); @@ -271,10 +274,12 @@ static void pututline_my(pstring uname, struct utmp *u, BOOL claim) #endif /* HAVE_PUTUTLINE */ #ifndef HAVE_UPDWTMP + /**************************************************************************** -Update wtmp file directly. No subroutine interface: probably a BSD system. -Credit: Michail Vidiassov <master@iaas.msu.ru> + Update wtmp file directly. No subroutine interface: probably a BSD system. + Credit: Michail Vidiassov <master@iaas.msu.ru> ****************************************************************************/ + static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim) { int fd; @@ -294,8 +299,8 @@ static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim) * man page appears not to specify (hints non-NULL) * A correspondent suggest at least ut_name should be NULL */ - memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name)); - memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host)); + memset((char *)&u->ut_name, '\0', sizeof(u->ut_name)); + memset((char *)&u->ut_host, '\0', sizeof(u->ut_host)); } /* Stolen from logwtmp function in libutil. * May be more locking/blocking is needed? @@ -311,9 +316,10 @@ static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim) #endif /* HAVE_UPDWTMP */ /**************************************************************************** -Update via utmp/wtmp (not utmpx/wtmpx) + Update via utmp/wtmp (not utmpx/wtmpx). ****************************************************************************/ -static void utmp_nox_update(struct utmp *u, const char *host, BOOL claim) + +static void utmp_nox_update(struct utmp *u, BOOL claim) { pstring uname, wname; #if defined(PUTUTLINE_RETURNS_UTMP) @@ -369,21 +375,41 @@ static void utmp_nox_update(struct utmp *u, const char *host, BOOL claim) } /**************************************************************************** -Update via utmpx/wtmpx (preferred) or via utmp/wtmp + Copy a string in the utmp structure. ****************************************************************************/ + +static void utmp_strcpy(char *dest, const char *src, size_t n) +{ + size_t len = 0; + + memset(dest, '\0', n); + if (src) + len = strlen(src); + if (len >= n) { + memcpy(dest, src, n); + } else { + if (len) + memcpy(dest, src, len); + } +} + +/**************************************************************************** + Update via utmpx/wtmpx (preferred) or via utmp/wtmp. +****************************************************************************/ + static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim) { #if !defined(HAVE_UTMPX_H) /* No utmpx stuff. Drop to non-x stuff */ - utmp_nox_update(u, hostname, claim); + utmp_nox_update(u, claim); #elif !defined(HAVE_PUTUTXLINE) /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */ DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n")); - utmp_nox_update(u, hostname, claim); + utmp_nox_update(u, claim); #elif !defined(HAVE_GETUTMPX) /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */ DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n")); - utmp_nox_update(u, hostname, claim); + utmp_nox_update(u, claim); #else pstring uname, wname; struct utmpx ux, *uxrc; @@ -391,10 +417,12 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim) getutmpx(u, &ux); #if defined(HAVE_UX_UT_SYSLEN) - if (hostname) ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */ - else ux.ut_syslen = 0; + if (hostname) + ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */ + else + ux.ut_syslen = 0; #endif - safe_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host)-1); + utmp_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host)); uw_pathname(uname, "utmpx", ux_pathname); uw_pathname(wname, "wtmpx", wx_pathname); @@ -407,7 +435,7 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim) * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".) */ if ((strlen(uname) == 0) || (strlen(wname) == 0)) { - utmp_nox_update(u, hostname, claim); + utmp_nox_update(u, claim); } else { utmpxname(uname); setutxent(); @@ -424,8 +452,9 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim) #if defined(HAVE_UT_UT_ID) /**************************************************************************** -encode the unique connection number into "ut_id" + Encode the unique connection number into "ut_id". ****************************************************************************/ + static int ut_id_encode(int i, char *fourbyte) { int nbase; @@ -467,9 +496,9 @@ static BOOL sys_utmp_fill(struct utmp *u, * rather than to try to detect and optimise. */ #if defined(HAVE_UT_UT_USER) - safe_strcpy(u->ut_user, username, sizeof(u->ut_user)-1); + utmp_strcpy(u->ut_user, username, sizeof(u->ut_user)); #elif defined(HAVE_UT_UT_NAME) - safe_strcpy(u->ut_name, username, sizeof(u->ut_name)-1); + utmp_strcpy(u->ut_name, username, sizeof(u->ut_name)); #endif /* @@ -485,7 +514,7 @@ static BOOL sys_utmp_fill(struct utmp *u, id_str, sizeof(u->ut_line))); return False; } - memcpy(u->ut_line, id_str, sizeof(u->ut_line)); + utmp_strcpy(u->ut_line, id_str, sizeof(u->ut_line)); #if defined(HAVE_UT_UT_PID) u->ut_pid = sys_getpid(); @@ -508,7 +537,7 @@ static BOOL sys_utmp_fill(struct utmp *u, #endif #if defined(HAVE_UT_UT_HOST) - safe_strcpy(u->ut_host, hostname, sizeof(u->ut_host)-1); + utmp_strcpy(u->ut_host, hostname, sizeof(u->ut_host)); #endif #if defined(HAVE_UT_UT_ADDR) @@ -529,8 +558,9 @@ static BOOL sys_utmp_fill(struct utmp *u, } /**************************************************************************** -close a connection + Close a connection. ****************************************************************************/ + void sys_utmp_yield(const char *username, const char *hostname, const char *id_str, int id_num) { @@ -553,8 +583,9 @@ void sys_utmp_yield(const char *username, const char *hostname, } /**************************************************************************** -claim a entry in whatever utmp system the OS uses + Claim a entry in whatever utmp system the OS uses. ****************************************************************************/ + void sys_utmp_claim(const char *username, const char *hostname, const char *id_str, int id_num) { diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c index 8e579634249..7d84e8756eb 100644 --- a/source/smbd/vfs-wrap.c +++ b/source/smbd/vfs-wrap.c @@ -559,6 +559,62 @@ int vfswrap_utime(connection_struct *conn, char *path, struct utimbuf *times) return result; } +/********************************************************************* + A version of ftruncate that will write the space on disk if strict + allocate is set. +**********************************************************************/ + +static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) +{ + struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops; + SMB_STRUCT_STAT st; + SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR); + unsigned char zero_space[4096]; + SMB_OFF_T space_to_write = len - st.st_size; + + if (currpos == -1) + return -1; + + if (vfs_ops->fstat(fsp, fd, &st) == -1) + return -1; + +#ifdef S_ISFIFO + if (S_ISFIFO(st.st_mode)) + return 0; +#endif + + if (st.st_size == len) + return 0; + + /* Shrink - just ftruncate. */ + if (st.st_size > len) + return sys_ftruncate(fd, len); + + /* Write out the real space on disk. */ + if (vfs_ops->lseek(fsp, fd, st.st_size, SEEK_SET) != st.st_size) + return -1; + + space_to_write = len - st.st_size; + + memset(zero_space, '\0', sizeof(zero_space)); + while ( space_to_write > 0) { + SMB_OFF_T retlen; + SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write); + + retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write); + if (retlen <= 0) + return -1; + + space_to_write -= retlen; + } + + /* Seek to where we were */ + if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) + return -1; + + return 0; +} + int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) { int result = -1; @@ -569,13 +625,21 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) START_PROFILE(syscall_ftruncate); + if (lp_strict_allocate(SNUM(fsp->conn))) { + result = strict_allocate_ftruncate(fsp, fd, len); + END_PROFILE(syscall_ftruncate); + return result; + } + /* we used to just check HAVE_FTRUNCATE_EXTEND and only use sys_ftruncate if the system supports it. Then I discovered that you can have some filesystems that support ftruncate expansion and some that don't! On Linux fat can't do ftruncate extend but ext2 can. */ + result = sys_ftruncate(fd, len); - if (result == 0) goto done; + if (result == 0) + goto done; /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot extend a file with ftruncate. Provide alternate implementation @@ -589,7 +653,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) size in which case the ftruncate above should have succeeded or shorter, in which case seek to len - 1 and write 1 byte of zero */ - if (vfs_ops->fstat(fsp, fd, &st) < 0) { + if (vfs_ops->fstat(fsp, fd, &st) == -1) { goto done; } @@ -610,19 +674,17 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) goto done; } - if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1) { + if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1) goto done; - } - if (vfs_ops->write(fsp, fd, &c, 1)!=1) { + if (vfs_ops->write(fsp, fd, &c, 1)!=1) goto done; - } /* Seek to where we were */ - if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) { + if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) goto done; - } result = 0; + done: END_PROFILE(syscall_ftruncate); @@ -672,6 +734,51 @@ int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_ return result; } +int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath) +{ + int result; + + START_PROFILE(syscall_link); + +#ifdef VFS_CHECK_NULL + if ((oldpath == NULL) || (newpath == NULL)) + smb_panic("NULL pointer passed to vfswrap_link()\n"); +#endif + result = sys_link(oldpath, newpath); + END_PROFILE(syscall_link); + return result; +} + +int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev) +{ + int result; + + START_PROFILE(syscall_mknod); + +#ifdef VFS_CHECK_NULL + if (pathname == NULL) + smb_panic("NULL pointer passed to vfswrap_mknod()\n"); +#endif + result = sys_mknod(pathname, mode, dev); + END_PROFILE(syscall_mknod); + return result; +} + +char *vfswrap_realpath(connection_struct *conn, const char *path, char *resolved_path) +{ + char *result; + + START_PROFILE(syscall_realpath); + +#ifdef VFS_CHECK_NULL + if ((path == NULL) || (resolved_path == NULL)) + smb_panic("NULL pointer passed to vfswrap_realpath()\n"); +#endif + result = sys_realpath(path, resolved_path); + END_PROFILE(syscall_realpath); + return result; +} + size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc) { size_t result; diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c index 8d049b51c4a..229880c9f15 100644 --- a/source/smbd/vfs.c +++ b/source/smbd/vfs.c @@ -21,8 +21,6 @@ #include "includes.h" -extern int DEBUGLEVEL; - /* Some structures to help us initialise the vfs operations table */ struct vfs_syminfo { @@ -74,6 +72,9 @@ struct vfs_ops default_vfs_ops = { vfswrap_lock, vfswrap_symlink, vfswrap_readlink, + vfswrap_link, + vfswrap_mknod, + vfswrap_realpath, vfswrap_fget_nt_acl, vfswrap_get_nt_acl, @@ -240,6 +241,12 @@ static BOOL vfs_init_custom(connection_struct *conn) if (conn->vfs_ops.readlink == NULL) conn->vfs_ops.readlink = default_vfs_ops.readlink; + if (conn->vfs_ops.link == NULL) + conn->vfs_ops.link = default_vfs_ops.link; + + if (conn->vfs_ops.mknod == NULL) + conn->vfs_ops.mknod = default_vfs_ops.mknod; + if (conn->vfs_ops.fget_nt_acl == NULL) conn->vfs_ops.fget_nt_acl = default_vfs_ops.fget_nt_acl; @@ -350,10 +357,10 @@ char *vfs_getwd(connection_struct *conn, char *unix_path) } /******************************************************************* - Check if a vfs file exists. + Check if an object exists in the vfs. ********************************************************************/ -BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf) +BOOL vfs_object_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf) { SMB_STRUCT_STAT st; @@ -362,9 +369,26 @@ BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf) ZERO_STRUCTP(sbuf); - if (vfs_stat(conn,fname,sbuf) != 0) + if (vfs_stat(conn,fname,sbuf) == -1) return(False); + return True; +} +/******************************************************************* + Check if a file exists in the vfs. +********************************************************************/ + +BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf) +{ + SMB_STRUCT_STAT st; + + if (!sbuf) + sbuf = &st; + + ZERO_STRUCTP(sbuf); + + if (vfs_stat(conn,fname,sbuf) == -1) + return False; return(S_ISREG(sbuf->st_mode)); } @@ -399,19 +423,21 @@ ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N) { - size_t total=0; - ssize_t ret; + size_t total=0; + ssize_t ret; - while (total < N) - { - ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total); + while (total < N) { + ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total); - if (ret == -1) return -1; - if (ret == 0) return total; + if (ret == -1) + return -1; + if (ret == 0) + return total; - total += ret; - } - return (ssize_t)total; + total += ret; + } + + return (ssize_t)total; } /**************************************************************************** @@ -424,11 +450,11 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len) { int ret; SMB_STRUCT_STAT st; - struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops; + connection_struct *conn = fsp->conn; + struct vfs_ops *vfs_ops = &conn->vfs_ops; + SMB_OFF_T space_avail; + SMB_BIG_UINT bsize,dfree,dsize; - if (!lp_strict_allocate(SNUM(fsp->conn))) - return vfs_set_filelen(fsp, len); - release_level_2_oplocks_on_change(fsp); /* @@ -450,47 +476,30 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len) DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n", fsp->fsp_name, (double)st.st_size )); + flush_write_cache(fsp, SIZECHANGE_FLUSH); if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) { set_filelen_write_cache(fsp, len); } return ret; } - /* Grow - we need to write out the space.... */ - { - static unsigned char zero_space[65536]; - - SMB_OFF_T start_pos = st.st_size; - SMB_OFF_T len_to_write = len - st.st_size; - SMB_OFF_T retlen; + /* Grow - we need to test if we have enough space. */ - DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f\n", - fsp->fsp_name, (double)st.st_size )); + if (!lp_strict_allocate(SNUM(fsp->conn))) + return 0; - if ((retlen = vfs_ops->lseek(fsp, fsp->fd, start_pos, SEEK_SET)) != start_pos) - return -1; + len -= st.st_size; + len /= 1024; /* Len is now number of 1k blocks needed. */ + space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); - while ( len_to_write > 0) { - SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),len_to_write); - - retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write); - if (retlen <= 0) { - /* Write fail - return to original size. */ - int save_errno = errno; - fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, st.st_size); - errno = save_errno; - DEBUG(10,("vfs_allocate_file_space: file %s, grow. write fail %s\n", - fsp->fsp_name, strerror(errno) )); - return -1; - } + DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n", + fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail )); - DEBUG(10,("vfs_allocate_file_space: file %s, grow. wrote %.0f\n", - fsp->fsp_name, (double)retlen )); - - len_to_write -= retlen; - } - set_filelen_write_cache(fsp, len); + if (len > space_avail) { + errno = ENOSPC; + return -1; } + return 0; } @@ -505,6 +514,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) int ret; release_level_2_oplocks_on_change(fsp); + DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); + flush_write_cache(fsp, SIZECHANGE_FLUSH); if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1) set_filelen_write_cache(fsp, len); @@ -696,7 +707,7 @@ static void array_promote(char *array,int elsize,int element) memcpy(p,array + element * elsize, elsize); memmove(array + elsize,array,elsize*element); memcpy(array,p,elsize); - free(p); + SAFE_FREE(p); } /******************************************************************* |