diff options
author | CVS Import User <samba-bugs@samba.org> | 2004-04-04 11:51:10 +0000 |
---|---|---|
committer | CVS Import User <samba-bugs@samba.org> | 2004-04-04 11:51:10 +0000 |
commit | e3d2dbdff6711b0bc768fb6b08f41240f21d5fba (patch) | |
tree | 159ef54b59b18e9b950f5c6af105915214244912 /source/smbd | |
parent | 139b1658ca30692835c1a7203c7cd003e587ac12 (diff) | |
download | samba-e3d2dbdff6711b0bc768fb6b08f41240f21d5fba.tar.gz samba-e3d2dbdff6711b0bc768fb6b08f41240f21d5fba.tar.xz samba-e3d2dbdff6711b0bc768fb6b08f41240f21d5fba.zip |
r6: merge in the samba4 HEAD branch from cvs
to checkout try:
svn co svn+ssh://svn.samba.org/home/svn/samba/branches/SAMBA_4_0
metze
Diffstat (limited to 'source/smbd')
60 files changed, 1815 insertions, 43005 deletions
diff --git a/source/smbd/.cvsignore b/source/smbd/.cvsignore index d2b1fd5b2ee..5f2a5c4cf75 100644 --- a/source/smbd/.cvsignore +++ b/source/smbd/.cvsignore @@ -1,3 +1,2 @@ *.po *.po32 -build_options.c diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c deleted file mode 100644 index c0512d5539b..00000000000 --- a/source/smbd/blocking.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Blocking Locking functions - Copyright (C) Jeremy Allison 1998-2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern char *OutBuffer; - -/**************************************************************************** - This is the structure to queue to implement blocking locks. - notify. It consists of the requesting SMB and the expiry time. -*****************************************************************************/ - -typedef struct { - ubi_slNode msg_next; - int com_type; - files_struct *fsp; - time_t expire_time; - int lock_num; - SMB_BIG_UINT offset; - SMB_BIG_UINT count; - uint16 lock_pid; - char *inbuf; - int length; -} blocking_lock_record; - -static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_queue, 0}; - -/**************************************************************************** - Destructor for the above structure. -****************************************************************************/ - -static void free_blocking_lock_record(blocking_lock_record *blr) -{ - SAFE_FREE(blr->inbuf); - SAFE_FREE(blr); -} - -/**************************************************************************** - Get the files_struct given a particular queued SMB. -*****************************************************************************/ - -static files_struct *get_fsp_from_pkt(char *inbuf) -{ - switch(CVAL(inbuf,smb_com)) { - case SMBlock: - case SMBlockread: - return file_fsp(inbuf,smb_vwv0); - case SMBlockingX: - return file_fsp(inbuf,smb_vwv2); - default: - DEBUG(0,("get_fsp_from_pkt: PANIC - unknown type on blocking lock queue - exiting.!\n")); - exit_server("PANIC - unknown type on blocking lock queue"); - } - return NULL; /* Keep compiler happy. */ -} - -/**************************************************************************** - Determine if this is a secondary element of a chained SMB. - **************************************************************************/ - -static BOOL in_chained_smb(void) -{ - return (chain_size != 0); -} - -static void received_unlock_msg(int msg_type, pid_t src, void *buf, size_t len); - -/**************************************************************************** - Function to push a blocking lock request onto the lock queue. -****************************************************************************/ - -BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, - int lock_num, uint16 lock_pid, SMB_BIG_UINT offset, SMB_BIG_UINT count) -{ - static BOOL set_lock_msg; - blocking_lock_record *blr; - BOOL my_lock_ctx = False; - NTSTATUS status; - - if(in_chained_smb() ) { - DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n")); - return False; - } - - /* - * Now queue an entry on the blocking lock queue. We setup - * the expiration time here. - */ - - if((blr = (blocking_lock_record *)malloc(sizeof(blocking_lock_record))) == NULL) { - DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" )); - return False; - } - - if((blr->inbuf = (char *)malloc(length)) == NULL) { - DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" )); - SAFE_FREE(blr); - return False; - } - - blr->com_type = CVAL(inbuf,smb_com); - blr->fsp = get_fsp_from_pkt(inbuf); - blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout; - blr->lock_num = lock_num; - blr->lock_pid = lock_pid; - blr->offset = offset; - blr->count = count; - memcpy(blr->inbuf, inbuf, length); - blr->length = length; - - /* Add a pending lock record for this. */ - status = brl_lock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum, - lock_pid, sys_getpid(), blr->fsp->conn->cnum, - offset, count, PENDING_LOCK, &my_lock_ctx); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n")); - free_blocking_lock_record(blr); - return False; - } - - ubi_slAddTail(&blocking_lock_queue, blr); - - /* Ensure we'll receive messages when this is unlocked. */ - if (!set_lock_msg) { - message_register(MSG_SMB_UNLOCK, received_unlock_msg); - set_lock_msg = True; - } - - DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \ -for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout, - blr->fsp->fnum, blr->fsp->fsp_name )); - - /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); - - return True; -} - -/**************************************************************************** - Return a smd with a given size. -*****************************************************************************/ - -static void send_blocking_reply(char *outbuf, int outsize) -{ - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_blocking_reply: send_smb failed."); -} - -/**************************************************************************** - Return a lockingX success SMB. -*****************************************************************************/ - -static void reply_lockingX_success(blocking_lock_record *blr) -{ - char *outbuf = OutBuffer; - int bufsize = BUFFER_SIZE; - char *inbuf = blr->inbuf; - int outsize = 0; - - construct_reply_common(inbuf, outbuf); - set_message(outbuf,2,0,True); - - /* - * As this message is a lockingX call we must handle - * any following chained message correctly. - * This is normally handled in construct_reply(), - * but as that calls switch_message, we can't use - * that here and must set up the chain info manually. - */ - - outsize = chain_reply(inbuf,outbuf,blr->length,bufsize); - - outsize += chain_size; - - send_blocking_reply(outbuf,outsize); -} - -/**************************************************************************** - Return a generic lock fail error blocking call. -*****************************************************************************/ - -static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status) -{ - char *outbuf = OutBuffer; - char *inbuf = blr->inbuf; - construct_reply_common(inbuf, outbuf); - - /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to - FILE_LOCK_CONFLICT! (tridge) */ - if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { - status = NT_STATUS_FILE_LOCK_CONFLICT; - } - - ERROR_NT(status); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("generic_blocking_lock_error: send_smb failed."); -} - -/**************************************************************************** - Return a lock fail error for a lockingX call. Undo all the locks we have - obtained first. -*****************************************************************************/ - -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--) { - 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, NTSTATUS status) -{ - 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"); - } -} - -/**************************************************************************** - Attempt to finish off getting all pending blocking locks for a lockread call. - Returns True if we want to be removed from the list. -*****************************************************************************/ - -static BOOL process_lockread(blocking_lock_record *blr) -{ - char *outbuf = OutBuffer; - char *inbuf = blr->inbuf; - ssize_t nread = -1; - char *data, *p; - int outsize = 0; - SMB_BIG_UINT startpos; - size_t numtoread; - NTSTATUS status; - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - files_struct *fsp = blr->fsp; - BOOL my_lock_ctx = False; - - numtoread = SVAL(inbuf,smb_vwv1); - startpos = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv2); - - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; - - status = do_lock_spin( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, startpos, READ_LOCK, &my_lock_ctx); - if (NT_STATUS_V(status)) { - if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && - !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { - /* - * We have other than a "can't get lock" - * 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; -} - -/**************************************************************************** - Attempt to finish off getting all pending blocking locks for a lock call. - Returns True if we want to be removed from the list. -*****************************************************************************/ - -static BOOL process_lock(blocking_lock_record *blr) -{ - char *outbuf = OutBuffer; - char *inbuf = blr->inbuf; - int outsize; - SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0; - NTSTATUS status; - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - files_struct *fsp = blr->fsp; - BOOL my_lock_ctx = False; - - count = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1); - offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3); - - errno = 0; - status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx); - if (NT_STATUS_IS_ERR(status)) { - if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && - !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { - /* - * We have other than a "can't get lock" - * 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; -} - -/**************************************************************************** - Attempt to finish off getting all pending blocking locks for a lockingX call. - Returns True if we want to be removed from the list. -*****************************************************************************/ - -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; - BOOL my_lock_ctx = False; - 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_spin(fsp,conn,lock_pid,count,offset, - ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx); - 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 (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && - !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { - /* - * We have other than a "can't get lock" - * 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; -} - -/**************************************************************************** - Process a blocking lock SMB. - Returns True if we want to be removed from the list. -*****************************************************************************/ - -static BOOL blocking_lock_record_process(blocking_lock_record *blr) -{ - switch(blr->com_type) { - case SMBlock: - return process_lock(blr); - case SMBlockread: - return process_lockread(blr); - case SMBlockingX: - return process_lockingX(blr); - default: - DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n")); - exit_server("PANIC - unknown type on blocking lock queue"); - } - return False; /* Keep compiler happy. */ -} - -/**************************************************************************** - Delete entries by fnum from the blocking lock pending queue. -*****************************************************************************/ - -void remove_pending_lock_requests_by_fid(files_struct *fsp) -{ - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; - - while(blr != NULL) { - if(blr->fsp->fnum == fsp->fnum) { - - DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \ -file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); - - brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum, - blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum, - blr->offset, blr->count, True, NULL, NULL); - - 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; - } - - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); - } -} - -/**************************************************************************** - Delete entries by mid from the blocking lock pending queue. Always send reply. -*****************************************************************************/ - -void remove_pending_lock_requests_by_mid(int mid) -{ - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; - - while(blr != NULL) { - if(SVAL(blr->inbuf,smb_mid) == mid) { - files_struct *fsp = blr->fsp; - - 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,NT_STATUS_FILE_LOCK_CONFLICT); - brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum, - blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum, - blr->offset, blr->count, True, NULL, NULL); - 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; - } - - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); - } -} - -/**************************************************************************** - Set a flag as an unlock request affects one of our pending locks. -*****************************************************************************/ - -static void received_unlock_msg(int msg_type, pid_t src, void *buf, size_t len) -{ - DEBUG(10,("received_unlock_msg\n")); - process_blocking_lock_queue(time(NULL)); -} - -/**************************************************************************** - Return the number of seconds to the next blocking locks timeout, or default_timeout -*****************************************************************************/ - -unsigned blocking_locks_timeout(unsigned default_timeout) -{ - unsigned timeout = default_timeout; - time_t t; - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst(&blocking_lock_queue); - - /* note that we avoid the time() syscall if there are no blocking locks */ - if (!blr) - return timeout; - - t = time(NULL); - - while (blr) { - if ((blr->expire_time != (time_t)-1) && - (timeout > (blr->expire_time - t))) { - timeout = blr->expire_time - t; - } - blr = (blocking_lock_record *)ubi_slNext(blr); - } - - if (timeout < 1) - timeout = 1; - - return timeout; -} - -/**************************************************************************** - Process the blocking lock queue. Note that this is only called as root. -*****************************************************************************/ - -void process_blocking_lock_queue(time_t t) -{ - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; - - if(blr == NULL) - return; - - /* - * Go through the queue and see if we can get any of the locks. - */ - - while(blr != NULL) { - connection_struct *conn = NULL; - uint16 vuid; - files_struct *fsp = NULL; - - /* - * Ensure we don't have any old chain_fsp values - * sitting around.... - */ - chain_size = 0; - file_chain_reset(); - fsp = blr->fsp; - - conn = conn_find(SVAL(blr->inbuf,smb_tid)); - vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : - SVAL(blr->inbuf,smb_uid); - - DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n", - fsp->fnum, fsp->fsp_name )); - - if((blr->expire_time != -1) && (blr->expire_time <= t)) { - /* - * Lock expired - throw away all previously - * obtained locks and return lock error. - */ - DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n", - fsp->fnum, fsp->fsp_name )); - - brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - blr->lock_pid, sys_getpid(), conn->cnum, - blr->offset, blr->count, True, NULL, NULL); - - blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); - 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(!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,NT_STATUS_ACCESS_DENIED); - - brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - blr->lock_pid, sys_getpid(), conn->cnum, - blr->offset, blr->count, True, NULL, NULL); - - 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(!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,NT_STATUS_ACCESS_DENIED); - - brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - blr->lock_pid, sys_getpid(), conn->cnum, - blr->offset, blr->count, True, NULL, NULL); - - 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)); - change_to_root_user(); - continue; - } - - /* - * Go through the remaining locks and try and obtain them. - * The call returns True if all locks were obtained successfully - * and False if we still need to wait. - */ - - if(blocking_lock_record_process(blr)) { - - brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - blr->lock_pid, sys_getpid(), conn->cnum, - blr->offset, blr->count, True, NULL, NULL); - - 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)); - change_to_root_user(); - continue; - } - - change_to_root_user(); - - /* - * Move to the next in the list. - */ - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); - } -} diff --git a/source/smbd/build_options.c b/source/smbd/build_options.c new file mode 100644 index 00000000000..e450fee4363 --- /dev/null +++ b/source/smbd/build_options.c @@ -0,0 +1,535 @@ +/* + Unix SMB/CIFS implementation. + Build Options for Samba Suite + Copyright (C) Vance Lankhaar <vlankhaar@hotmail.com> 2001 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "build_env.h" +#include "dynconfig.h" + +static void output(BOOL screen, const char *format, ...) PRINTF_ATTRIBUTE(2,3); + +/* +#define OUTPUT(x) snprintf(outstring,sizeof(outstring),x); output(screen,outstring); +*/ +/**************************************************************************** +helper function for build_options +****************************************************************************/ +static void output(BOOL screen, const char *format, ...) +{ + char *ptr; + va_list ap; + + va_start(ap, format); + vasprintf(&ptr,format,ap); + va_end(ap); + + if (screen) { + d_printf("%s", ptr); + } else { + DEBUG(4,("%s", ptr)); + } + + SAFE_FREE(ptr); +} + +/**************************************************************************** +options set at build time for the samba suite +****************************************************************************/ +void build_options(BOOL screen) +{ + if ((DEBUGLEVEL < 4) && (!screen)) { + return; + } + +#ifdef _BUILD_ENV_H + /* Output information about the build environment */ + output(screen,"Build environment:\n"); + output(screen," Built by: %s@%s\n",BUILD_ENV_USER,BUILD_ENV_HOST); + output(screen," Built on: %s\n",BUILD_ENV_DATE); + + output(screen," Built using: %s\n",BUILD_ENV_COMPILER); + output(screen," Build host: %s\n",BUILD_ENV_UNAME); + output(screen," SRCDIR: %s\n",BUILD_ENV_SRCDIR); + output(screen," BUILDDIR: %s\n",BUILD_ENV_BUILDDIR); + + +#endif + + /* Output various options (most correspond to --with options) */ + output(screen,"\nBuild options:\n"); +#ifdef WITH_SMBWRAPPER + output(screen," WITH_SMBWRAPPER\n"); +#endif +#ifdef WITH_AFS + output(screen," WITH_AFS\n"); +#endif +#ifdef WITH_DFS + output(screen," WITH_DFS\n"); +#endif +#ifdef KRB4_AUTH + output(screen," KRB4_AUTH"); +#endif +#ifdef HAVE_KRB5 + output(screen," HAVE_KRB5"); +#endif +#ifdef HAVE_GSSAPI + output(screen," HAVE_GSSAPI"); +#endif +#ifdef HAVE_LDAP + output(screen," HAVE_LDAP"); +#endif +#ifdef WITH_AUTOMOUNT + output(screen," WITH_AUTOMOUNT\n"); +#endif +#ifdef WITH_SMBMOUNT + output(screen," WITH_SMBMOUNT\n"); +#endif +#ifdef WITH_PAM + output(screen," WITH_PAM\n"); +#endif +#ifdef WITH_TDB_SAM + output(screen," WITH_TDB_SAM\n"); +#endif +#ifdef WITH_SMBPASSWD_SAM + output(screen," WITH_SMBPASSWD_SAM\n"); +#endif +#ifdef WITH_NISPLUS_SAM + output(screen," WITH_NISPLUS_SAM\n"); +#endif +#ifdef WITH_NISPLUS_HOME + output(screen," WITH_NISPLUS_HOME\n"); +#endif +#ifdef WITH_SYSLOG + output(screen," WITH_SYSLOG\n"); +#endif +#ifdef WITH_QUOTAS + output(screen," WITH_QUOTAS\n"); +#endif +#ifdef WITH_VFS + output(screen," WITH_VFS\n"); +#endif +#ifdef USE_SPINLOCKS + output(screen," USE_SPINLOCKS\n"); +#endif +#ifdef SPARC_SPINLOCKS + output(screen," SPARC_SPINLOCKS\n"); +#endif +#ifdef INTEL_SPINLOCKS + output(screen," INTEL_SPINLOCKS\n"); +#endif +#ifdef MIPS_SPINLOCKS + output(screen," MIPS_SPINLOCKS\n"); +#endif +#ifdef POWERPC_SPINLOCKS + output(screen," POWERPC_SPINLOCKS\n"); +#endif +#ifdef HAVE_UNIXWARE_ACLS + output(screen," HAVE_UNIXWARE_ACLS\n"); +#endif +#ifdef HAVE_SOLARIS_ACLS + output(screen," HAVE_SOLARIS_ACLS\n"); +#endif +#ifdef HAVE_IRIX_ACLS + output(screen," HAVE_IRIX_ACLS\n"); +#endif +#ifdef HAVE_AIX_ACLS + output(screen," HAVE_AIX_ACLS\n"); +#endif +#ifdef HAVE_POSIX_ACLS + output(screen," HAVE_POSIX_ACLS\n"); +#endif +#ifdef HAVE_TRU64_ACLS + output(screen," HAVE_TRU64_ACLS\n"); +#endif + +#ifdef HAVE_ACL_GET_PERM_NP + output(screen," HAVE_ACL_GET_PERM_NP\n"); +#endif +#ifdef HAVE_NO_ACLS + output(screen," HAVE_NO_ACLS\n"); +#endif +#ifdef HAVE_LIBREADLINE + output(screen," HAVE_LIBREADLINE\n"); +#endif +#ifdef WITH_LIBICONV + output(screen," WITH_LIBICONV: %s\n",WITH_LIBICONV); +#endif + + + /* Output various paths to files and directories */ + output(screen,"\nPaths:\n"); + output(screen," CONFIGFILE: %s\n", dyn_CONFIGFILE); +#ifdef PRIVATE_DIR + output(screen," PRIVATE_DIR: %s\n",PRIVATE_DIR); +#endif +#ifdef LMHOSTSFILE + output(screen," LMHOSTSFILE: %s\n",LMHOSTSFILE); +#endif + output(screen," SBINDIR: %s\n", dyn_SBINDIR); + output(screen," BINDIR: %s\n", dyn_BINDIR); + output(screen," LOCKDIR: %s\n",dyn_LOCKDIR); + output(screen," LOGFILEBASE: %s\n", dyn_LOGFILEBASE); + + /*Output various other options (most map to defines in the configure script*/ + output(screen,"\nOther Build Options:\n"); +#ifdef HAVE_VOLATILE + output(screen," HAVE_VOLATILE\n"); +#endif +#ifdef HAVE_SHADOW_H + output(screen," HAVE_SHADOW_H\n"); +#endif +#ifdef HAVE_CRYPT + output(screen," HAVE_CRYPT\n"); +#endif +#ifdef USE_BOTH_CRYPT_CALLS + output(screen," USE_BOTH_CRYPT_CALLS\n"); +#endif +#ifdef HAVE_TRUNCATED_SALT + output(screen," HAVE_TRUNCATED_SALT\n"); +#endif +#ifdef HAVE_CUPS + output(screen," HAVE_CUPS\n"); +#endif +#ifdef HAVE_CUPS_CUPS_H + output(screen," HAVE_CUPS_CUPS_H\n"); +#endif +#ifdef HAVE_CUPS_LANGUAGE_H + output(screen," HAVE_CUPS_LANGUAGE_H\n"); +#endif +#ifdef HAVE_DLOPEN + output(screen," HAVE_DLOPEN\n"); +#endif +#ifdef HAVE_DLCLOSE + output(screen," HAVE_DLCLOSE\n"); +#endif +#ifdef HAVE_DLSYM + output(screen," HAVE_DLSYM\n"); +#endif +#ifdef HAVE_DLERROR + output(screen," HAVE_DLERROR\n"); +#endif +#ifdef HAVE_UNIXSOCKET + output(screen," HAVE_UNIXSOCKET\n"); +#endif +#ifdef HAVE_SOCKLEN_T_TYPE + output(screen," HAVE_SOCKLEN_T_TYPE\n"); +#endif +#ifdef HAVE_SIG_ATOMIC_T_TYPE + output(screen," HAVE_SIG_ATOMIC_T_TYPE\n"); +#endif +#ifdef HAVE_SETRESUID + output(screen," HAVE_SETRESUID\n"); +#endif +#ifdef HAVE_SETRESGID + output(screen," HAVE_SETRESGID\n"); +#endif +#ifdef HAVE_CONNECT + output(screen," HAVE_CONNECT\n"); +#endif +#ifdef HAVE_YP_GET_DEFAULT_DOMAIN + output(screen," HAVE_YP_GET_DEFAULT_DOMAIN\n"); +#endif +#ifdef HAVE_STAT64 + output(screen," HAVE_STAT64\n"); +#endif +#ifdef HAVE_LSTAT64 + output(screen," HAVE_LSTAT64\n"); +#endif +#ifdef HAVE_FSTAT64 + output(screen," HAVE_FSTAT64\n"); +#endif +#ifdef HAVE_STRCASECMP + output(screen," HAVE_STRCASECMP\n"); +#endif +#ifdef HAVE_MEMSET + output(screen," HAVE_MEMSET\n"); +#endif +#ifdef HAVE_LONGLONG + output(screen," HAVE_LONGLONG\n"); +#endif +#ifdef COMPILER_SUPPORTS_LL + output(screen," COMPILER_SUPPORTS_LL\n"); +#endif +#ifdef SIZEOF_OFF_T + output(screen," SIZEOF_OFF_T: %d\n",SIZEOF_OFF_T); +#endif +#ifdef HAVE_OFF64_T + output(screen," HAVE_OFF64_T\n"); +#endif +#ifdef SIZEOF_INO_T + output(screen," SIZEOF_INO_T: %d\n",SIZEOF_INO_T); +#endif +#ifdef HAVE_INO64_T + output(screen," HAVE_INO64_T\n"); +#endif +#ifdef HAVE_STRUCT_DIRENT64 + output(screen," HAVE_STRUCT_DIRENT64\n"); +#endif +#ifdef HAVE_UNSIGNED_CHAR + output(screen," HAVE_UNSIGNED_CHAR\n"); +#endif +#ifdef HAVE_SOCK_SIN_LEN + output(screen," HAVE_SOCK_SIN_LEN\n"); +#endif +#ifdef SEEKDIR_RETURNS_VOID + output(screen," SEEKDIR_RETURNS_VOID\n"); +#endif +#ifdef HAVE_FUNCTION_MACRO + output(screen," HAVE_FUNCTION_MACRO\n"); +#endif +#ifdef HAVE_GETTIMEOFDAY + output(screen," HAVE_GETTIMEOFDAY\n"); +#endif +#ifdef HAVE_C99_VSNPRINTF + output(screen," HAVE_C99_VSNPRINTF\n"); +#endif +#ifdef HAVE_BROKEN_READDIR + output(screen," HAVE_BROKEN_READDIR\n"); +#endif +#ifdef HAVE_NATIVE_ICONV + output(screen," HAVE_NATIVE_ICONV\n"); +#endif +#ifdef HAVE_KERNEL_OPLOCKS_LINUX + output(screen," HAVE_KERNEL_OPLOCKS_LINUX\n"); +#endif +#ifdef HAVE_KERNEL_CHANGE_NOTIFY + output(screen," HAVE_KERNEL_CHANGE_NOTIFY\n"); +#endif +#ifdef HAVE_KERNEL_SHARE_MODES + output(screen," HAVE_KERNEL_SHARE_MODES\n"); +#endif +#ifdef HAVE_KERNEL_OPLOCKS_IRIX + output(screen," HAVE_KERNEL_OPLOCKS_IRIX\n"); +#endif +#ifdef HAVE_IRIX_SPECIFIC_CAPABILITIES + output(screen," HAVE_IRIX_SPECIFIC_CAPABILITIES\n"); +#endif +#ifdef HAVE_INT16_FROM_RPC_RPC_H + output(screen," HAVE_INT16_FROM_RPC_RPC_H\n"); +#endif +#ifdef HAVE_UINT16_FROM_RPC_RPC_H + output(screen," HAVE_UINT16_FROM_RPC_RPC_H\n"); +#endif +#ifdef HAVE_INT32_FROM_RPC_RPC_H + output(screen," HAVE_INT16_FROM_RPC_RPC_H\n"); +#endif +#ifdef HAVE_UINT32_FROM_RPC_RPC_H + output(screen," HAVE_UINT32_FROM_RPC_RPC_H\n"); +#endif +#ifdef HAVE_RPC_AUTH_ERROR_CONFLICT + output(screen," HAVE_RPC_AUTH_ERROR_CONFLICT\n"); +#endif +#ifdef HAVE_FTRUNCATE_EXTEND + output(screen," HAVE_FTRUNCATE_EXTEND\n"); +#endif +#ifdef HAVE_WORKING_AF_LOCAL + output(screen," HAVE_WORKING_AF_LOCAL\n"); +#endif +#ifdef HAVE_BROKEN_GETGROUPS + output(screen," HAVE_BROKEN_GETGROUPS\n"); +#endif +#ifdef REPLACE_GETPASS + output(screen," REPLACE_GETPASS\n"); +#endif +#ifdef REPLACE_INET_NTOA + output(screen," REPLACE_INET_NTOA\n"); +#endif +#ifdef HAVE_SECURE_MKSTEMP + output(screen," HAVE_SECURE_MKSTEMP\n"); +#endif +#ifdef SYSCONF_SC_NGROUPS_MAX + output(screen," SYSCONF_SC_NGROUPS_MAX\n"); +#endif +#ifdef HAVE_IFACE_AIX + output(screen," HAVE_IFACE_AIX\n"); +#endif +#ifdef HAVE_IFACE_IFCONF + output(screen," HAVE_IFACE_IFCONF\n"); +#endif +#ifdef HAVE_IFACE_IFREQ + output(screen," HAVE_IFACE_IFREQ\n"); +#endif +#ifdef USE_SETRESUID + output(screen," USE_SETRESUID\n"); +#endif +#ifdef USE_SETRESGID + output(screen," USE_SETREUID\n"); +#endif +#ifdef USE_SETEUID + output(screen," USE_SETEUID\n"); +#endif +#ifdef USE_SETUIDX + output(screen," USE_SETUIDX\n"); +#endif +#ifdef HAVE_MMAP + output(screen," HAVE_MMAP\n"); +#endif +#ifdef MMAP_BLACKLIST + output(screen," MMAP_BLACKLIST\n"); +#endif +#ifdef FTRUNCATE_NEEDS_ROOT + output(screen," FTRUNCATE_NEEDS_ROOT\n"); +#endif +#ifdef HAVE_FCNTL_LOCK + output(screen," HAVE_FCNTL_LOCK\n"); +#endif +#ifdef HAVE_BROKEN_FCNTL64_LOCKS + output(screen," HAVE_BROKEN_FCNTL64_LOCKS\n"); +#endif +#ifdef HAVE_STRUCT_FLOCK64 + output(screen," HAVE_STRUCT_FLOCK64\n"); +#endif +#ifdef BROKEN_NISPLUS_INCLUDE_FILES + output(screen," BROKEN_NISPLUS_INCLUDE_FILES\n"); +#endif +#ifdef HAVE_LIBPAM + output(screen," HAVE_LIBPAM\n"); +#endif +#ifdef STAT_STATVFS64 + output(screen," STAT_STATVFS64\n"); +#endif +#ifdef STAT_STATVFS + output(screen," STAT_STATVFS\n"); +#endif +#ifdef STAT_STATFS3_OSF1 + output(screen," STAT_STATFS3_OSF1\n"); +#endif +#ifdef STAT_STATFS2_BSIZE + output(screen," STAT_STATFS2_BSIZE\n"); +#endif +#ifdef STAT_STATFS4 + output(screen," STAT_STATFS4\n"); +#endif +#ifdef STAT_STATFS2_FSIZE + output(screen," STAT_STATFS2_FSIZE\n"); +#endif +#ifdef STAT_STATFS2_FS_DATA + output(screen," STAT_STATFS2_FS_DATA\n"); +#endif +#ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT + output(screen," HAVE_EXPLICIT_LARGEFILE_SUPPORT\n"); +#endif + +#ifdef WITH_UTMP + /* Output UTMP Stuff */ + output(screen,"\nUTMP Related:\n"); + output(screen," WITH_UTMP\n"); + +#ifdef HAVE_UTIMBUF + output(screen," HAVE_UTIMBUF\n"); +#endif +#ifdef HAVE_UT_UT_NAME + output(screen," HAVE_UT_UT_NAME\n"); +#endif +#ifdef HAVE_UT_UT_USER + output(screen," HAVE_UT_UT_USER\n"); +#endif +#ifdef HAVE_UT_UT_ID + output(screen," HAVE_UT_UT_ID\n"); +#endif +#ifdef HAVE_UT_UT_HOST + output(screen," HAVE_UT_UT_HOST\n"); +#endif +#ifdef HAVE_UT_UT_TIME + output(screen," HAVE_UT_UT_TIME\n"); +#endif +#ifdef HAVE_UT_UT_TV + output(screen," HAVE_UT_UT_TV\n"); +#endif +#ifdef HAVE_UT_UT_TYPE + output(screen," HAVE_UT_UT_TYPE\n"); +#endif +#ifdef HAVE_UT_UT_PID + output(screen," HAVE_UT_UT_PID\n"); +#endif +#ifdef HAVE_UT_UT_EXIT + output(screen," HAVE_UT_UT_EXIT\n"); +#endif +#ifdef HAVE_UT_UT_ADDR + output(screen," HAVE_UT_UT_ADDR\n"); +#endif +#ifdef PUTUTLINE_RETURNS_UTMP + output(screen," PUTUTLINE_RETURNS_UTMP\n"); +#endif +#ifdef HAVE_UX_UT_SYSLEN + output(screen," HAVE_UX_UT_SYSLEN\n"); +#endif +#endif /* WITH_UTMP */ + + /* Output Build OS */ + output(screen,"\nBuilt for host os:\n"); +#ifdef LINUX + output(screen," LINUX\n"); +#endif +#ifdef SUNOS5 + output(screen," SUNOS5\n"); +#endif +#ifdef SUNOS4 + output(screen," SUNOS4\n"); +#endif + /* BSD Isn't Defined in the configure script, but there is something about it in include/config.h.in (and I guess acconfig.h) */ +#ifdef BSD + output(screen," BSD\n"); +#endif +#ifdef IRIX + output(screen," IRIX\n"); +#endif +#ifdef IRIX6 + output(screen," IRIX6\n"); +#endif +#ifdef AIX + output(screen," AIX\n"); +#endif +#ifdef HPUX + output(screen," HPUX\n"); +#endif +#ifdef QNX + output(screen," QNX\n"); +#endif +#ifdef OSF1 + output(screen," OSF1\n"); +#endif +#ifdef SCO + output(screen," SCO\n"); +#endif +#ifdef UNIXWARE + output(screen," UNIXWARE\n"); +#endif +#ifdef NEXT2 + output(screen," NEXT2\n"); +#endif +#ifdef RELIANTUNIX + output(screen," RELIANTUNIX\n"); +#endif + + /* Output the sizes of the various types */ + output(screen,"\nType sizes:\n"); + output(screen," sizeof(char): %d\n",sizeof(char)); + output(screen," sizeof(int): %d\n",sizeof(int)); + output(screen," sizeof(long): %d\n",sizeof(long)); + output(screen," sizeof(uint8): %d\n",sizeof(uint8)); + output(screen," sizeof(uint16): %d\n",sizeof(uint16)); + output(screen," sizeof(uint32): %d\n",sizeof(uint32)); + output(screen," sizeof(short): %d\n",sizeof(short)); + output(screen," sizeof(void*): %d\n",sizeof(void*)); +} + + + diff --git a/source/smbd/change_trust_pw.c b/source/smbd/change_trust_pw.c deleted file mode 100644 index 1178400e4db..00000000000 --- a/source/smbd/change_trust_pw.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Periodic Trust account password changing. - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Paul Ashton 1997. - * Copyright (C) Jeremy Allison 1998. - * Copyright (C) Andrew Bartlett 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "includes.h" - -/************************************************************************ - Change the trust account password for a domain. -************************************************************************/ - -NTSTATUS change_trust_account_password( const char *domain, const char *remote_machine) -{ - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - struct in_addr pdc_ip; - fstring dc_name; - struct cli_state *cli; - - DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n", - domain)); - - if (remote_machine == NULL || !strcmp(remote_machine, "*")) { - /* Use the PDC *only* for this */ - - if ( !get_pdc_ip(domain, &pdc_ip) ) { - DEBUG(0,("Can't get IP for PDC for domain %s\n", domain)); - goto failed; - } - - if ( !name_status_find( domain, 0x1b, 0x20, pdc_ip, dc_name) ) - goto failed; - } else { - /* supoport old deprecated "smbpasswd -j DOMAIN -r MACHINE" behavior */ - fstrcpy( dc_name, remote_machine ); - } - - /* if this next call fails, then give up. We can't do - password changes on BDC's --jerry */ - - if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname(), dc_name, - NULL, 0, - "IPC$", "IPC", - "", "", - "", 0, Undefined, NULL))) { - DEBUG(0,("modify_trust_password: Connection to %s failed!\n", dc_name)); - nt_status = NT_STATUS_UNSUCCESSFUL; - goto failed; - } - - /* - * Ok - we have an anonymous connection to the IPC$ share. - * Now start the NT Domain stuff :-). - */ - - if(cli_nt_session_open(cli, PI_NETLOGON) == False) { - DEBUG(0,("modify_trust_password: unable to open the domain client session to machine %s. Error was : %s.\n", - dc_name, cli_errstr(cli))); - cli_nt_session_close(cli); - cli_ulogoff(cli); - cli_shutdown(cli); - nt_status = NT_STATUS_UNSUCCESSFUL; - goto failed; - } - - nt_status = trust_pw_find_change_and_store_it(cli, cli->mem_ctx, domain); - - cli_nt_session_close(cli); - cli_ulogoff(cli); - cli_shutdown(cli); - -failed: - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n", - timestring(False), domain)); - } - else - DEBUG(5,("change_trust_account_password: sucess!\n")); - - return nt_status; -} diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c deleted file mode 100644 index 4192cc3a239..00000000000 --- a/source/smbd/chgpasswd.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Samba utility functions - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001-2004 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* These comments regard the code to change the user's unix password: */ - -/* fork a child process to exec passwd and write to its - * tty to change a users password. This is running as the - * user who is attempting to change the password. - */ - -/* - * This code was copied/borrowed and stolen from various sources. - * The primary source was the poppasswd.c from the authors of POPMail. This software - * was included as a client to change passwords using the 'passwd' program - * on the remote machine. - * - * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson - * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences - * and rights to modify, distribute or incorporate this change to the CAP suite or - * using it for any other reason are granted, so long as this disclaimer is left intact. - */ - -/* - This code was hacked considerably for inclusion in Samba, primarily - by Andrew.Tridgell@anu.edu.au. The biggest change was the addition - of the "password chat" option, which allows the easy runtime - specification of the expected sequence of events to change a - password. - */ - -#include "includes.h" - -#ifdef HAVE_WORKING_CRACKLIB -#include <crack.h> - -#ifndef HAVE_CRACKLIB_DICTPATH -#ifndef CRACKLIB_DICTPATH -#define CRACKLIB_DICTPATH SAMBA_CRACKLIB_DICTPATH -#endif -#endif -#endif - -extern struct passdb_ops pdb_ops; - -static NTSTATUS check_oem_password(const char *user, - uchar password_encrypted_with_lm_hash[516], - const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], - const uchar old_nt_hash_encrypted[16], - SAM_ACCOUNT **hnd, char *new_passwd, - int new_passwd_size); - -#if ALLOW_CHANGE_PASSWORD - -static int findpty(char **slave) -{ - int master; - static fstring line; - DIR *dirp; - const char *dpname; - -#if defined(HAVE_GRANTPT) - /* Try to open /dev/ptmx. If that fails, fall through to old method. */ - if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) - { - grantpt(master); - unlockpt(master); - *slave = (char *)ptsname(master); - if (*slave == NULL) - { - DEBUG(0, - ("findpty: Unable to create master/slave pty pair.\n")); - /* Stop fd leak on error. */ - close(master); - return -1; - } - else - { - DEBUG(10, - ("findpty: Allocated slave pty %s\n", *slave)); - return (master); - } - } -#endif /* HAVE_GRANTPT */ - - fstrcpy(line, "/dev/ptyXX"); - - dirp = opendir("/dev"); - if (!dirp) - return (-1); - while ((dpname = readdirname(dirp)) != NULL) - { - if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) - { - DEBUG(3, - ("pty: try to open %s, line was %s\n", dpname, - line)); - line[8] = dpname[3]; - line[9] = dpname[4]; - if ((master = sys_open(line, O_RDWR, 0)) >= 0) - { - DEBUG(3, ("pty: opened %s\n", line)); - line[5] = 't'; - *slave = line; - closedir(dirp); - return (master); - } - } - } - closedir(dirp); - return (-1); -} - -static int dochild(int master, const char *slavedev, const struct passwd *pass, - const char *passwordprogram, BOOL as_root) -{ - int slave; - struct termios stermios; - gid_t gid; - uid_t uid; - - if (pass == NULL) - { - DEBUG(0, - ("dochild: user doesn't exist in the UNIX password database.\n")); - return False; - } - - gid = pass->pw_gid; - uid = pass->pw_uid; - - gain_root_privilege(); - - /* Start new session - gets rid of controlling terminal. */ - if (setsid() < 0) - { - DEBUG(3, - ("Weirdness, couldn't let go of controlling terminal\n")); - return (False); - } - - /* Open slave pty and acquire as new controlling terminal. */ - if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) - { - DEBUG(3, ("More weirdness, could not open %s\n", slavedev)); - return (False); - } -#ifdef I_PUSH - ioctl(slave, I_PUSH, "ptem"); - ioctl(slave, I_PUSH, "ldterm"); -#elif defined(TIOCSCTTY) - if (ioctl(slave, TIOCSCTTY, 0) < 0) - { - DEBUG(3, ("Error in ioctl call for slave pty\n")); - /* return(False); */ - } -#endif - - /* Close master. */ - close(master); - - /* Make slave stdin/out/err of child. */ - - if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO) - { - DEBUG(3, ("Could not re-direct stdin\n")); - return (False); - } - if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) - { - DEBUG(3, ("Could not re-direct stdout\n")); - return (False); - } - if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO) - { - DEBUG(3, ("Could not re-direct stderr\n")); - return (False); - } - if (slave > 2) - close(slave); - - /* Set proper terminal attributes - no echo, canonical input processing, - no map NL to CR/NL on output. */ - - if (tcgetattr(0, &stermios) < 0) - { - DEBUG(3, - ("could not read default terminal attributes on pty\n")); - return (False); - } - stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - stermios.c_lflag |= ICANON; -#ifdef ONLCR - stermios.c_oflag &= ~(ONLCR); -#endif - if (tcsetattr(0, TCSANOW, &stermios) < 0) - { - DEBUG(3, ("could not set attributes of pty\n")); - return (False); - } - - /* make us completely into the right uid */ - if (!as_root) - { - become_user_permanently(uid, gid); - } - - DEBUG(10, - ("Invoking '%s' as password change program.\n", - passwordprogram)); - - /* execl() password-change application */ - if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0) - { - DEBUG(3, ("Bad status returned from %s\n", passwordprogram)); - return (False); - } - return (True); -} - -static int expect(int master, char *issue, char *expected) -{ - pstring buffer; - int attempts, timeout, nread, len; - BOOL match = False; - - for (attempts = 0; attempts < 2; attempts++) { - if (!strequal(issue, ".")) { - if (lp_passwd_chat_debug()) - DEBUG(100, ("expect: sending [%s]\n", issue)); - - if ((len = write(master, issue, strlen(issue))) != strlen(issue)) { - DEBUG(2,("expect: (short) write returned %d\n", len )); - return False; - } - } - - if (strequal(expected, ".")) - return True; - - /* Initial timeout. */ - timeout = lp_passwd_chat_timeout() * 1000; - nread = 0; - buffer[nread] = 0; - - while ((len = read_socket_with_timeout(master, buffer + nread, 1, - sizeof(buffer) - nread - 1, - timeout)) > 0) { - nread += len; - buffer[nread] = 0; - - { - /* Eat leading/trailing whitespace before match. */ - pstring str; - pstrcpy( str, buffer); - trim_char( str, ' ', ' '); - - if ((match = (unix_wild_match(expected, str) == 0))) { - /* Now data has started to return, lower timeout. */ - timeout = lp_passwd_chat_timeout() * 100; - } - } - } - - if (lp_passwd_chat_debug()) - DEBUG(100, ("expect: expected [%s] received [%s] match %s\n", - expected, buffer, match ? "yes" : "no" )); - - if (match) - break; - - if (len < 0) { - DEBUG(2, ("expect: %s\n", strerror(errno))); - return False; - } - } - - DEBUG(10,("expect: returning %s\n", match ? "True" : "False" )); - return match; -} - -static void pwd_sub(char *buf) -{ - all_string_sub(buf, "\\n", "\n", 0); - all_string_sub(buf, "\\r", "\r", 0); - all_string_sub(buf, "\\s", " ", 0); - all_string_sub(buf, "\\t", "\t", 0); -} - -static int talktochild(int master, const char *seq) -{ - int count = 0; - fstring issue, expected; - - fstrcpy(issue, "."); - - while (next_token(&seq, expected, NULL, sizeof(expected))) - { - pwd_sub(expected); - count++; - - if (!expect(master, issue, expected)) - { - DEBUG(3, ("Response %d incorrect\n", count)); - return False; - } - - if (!next_token(&seq, issue, NULL, sizeof(issue))) - fstrcpy(issue, "."); - - 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); -} - -static BOOL chat_with_program(char *passwordprogram, struct passwd *pass, - char *chatsequence, BOOL as_root) -{ - char *slavedev; - int master; - pid_t pid, wpid; - int wstat; - BOOL chstat = False; - - if (pass == NULL) { - DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n")); - return False; - } - - /* allocate a pseudo-terminal device */ - if ((master = findpty(&slavedev)) < 0) { - DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name)); - return (False); - } - - /* - * We need to temporarily stop CatchChild from eating - * SIGCLD signals as it also eats the exit status code. JRA. - */ - - CatchChildLeaveStatus(); - - if ((pid = sys_fork()) < 0) { - DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name)); - close(master); - CatchChild(); - return (False); - } - - /* we now have a pty */ - if (pid > 0) { /* This is the parent process */ - if ((chstat = talktochild(master, chatsequence)) == False) { - DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name)); - kill(pid, SIGKILL); /* be sure to end this process */ - } - - while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { - if (errno == EINTR) { - errno = 0; - continue; - } - break; - } - - if (wpid < 0) { - DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n")); - close(master); - CatchChild(); - return (False); - } - - /* - * Go back to ignoring children. - */ - CatchChild(); - - close(master); - - if (pid != wpid) { - DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n")); - return (False); - } - if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) { - DEBUG(3, ("chat_with_program: The process exited with status %d \ -while we were waiting\n", WEXITSTATUS(wstat))); - return (False); - } -#if defined(WIFSIGNALLED) && defined(WTERMSIG) - else if (WIFSIGNALLED(wstat)) { - DEBUG(3, ("chat_with_program: The process was killed by signal %d \ -while we were waiting\n", WTERMSIG(wstat))); - return (False); - } -#endif - } else { - /* CHILD */ - - /* - * Lose any oplock capabilities. - */ - oplock_set_capability(False, False); - - /* make sure it doesn't freeze */ - alarm(20); - - if (as_root) - become_root(); - - DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name, - (int)getuid(), (int)getgid(), BOOLSTR(as_root) )); - chstat = dochild(master, slavedev, pass, passwordprogram, as_root); - - if (as_root) - unbecome_root(); - - /* - * The child should never return from dochild() .... - */ - - DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat)); - exit(1); - } - - if (chstat) - DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n", - (chstat ? "" : "un"), pass->pw_name)); - return (chstat); -} - -BOOL chgpasswd(const char *name, const struct passwd *pass, - const char *oldpass, const char *newpass, BOOL as_root) -{ - pstring passwordprogram; - pstring chatsequence; - size_t i; - size_t len; - - if (!oldpass) { - oldpass = ""; - } - - DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name)); - -#if DEBUG_PASSWORD - DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass)); -#endif - - /* Take the passed information and test it for minimum criteria */ - - /* Password is same as old password */ - if (strcmp(oldpass, newpass) == 0) { - /* don't allow same password */ - DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */ - return (False); /* inform the user */ - } - - /* - * Check the old and new passwords don't contain any control - * characters. - */ - - len = strlen(oldpass); - for (i = 0; i < len; i++) { - if (iscntrl((int)oldpass[i])) { - DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n")); - return False; - } - } - - len = strlen(newpass); - for (i = 0; i < len; i++) { - if (iscntrl((int)newpass[i])) { - DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n")); - return False; - } - } - -#ifdef WITH_PAM - if (lp_pam_password_change()) { - BOOL ret; - - if (as_root) - become_root(); - - if (pass) { - ret = smb_pam_passchange(pass->pw_name, oldpass, newpass); - } else { - ret = smb_pam_passchange(name, oldpass, newpass); - } - - if (as_root) - unbecome_root(); - - return ret; - } -#endif - - /* A non-PAM password change just doen't make sense without a valid local user */ - - if (pass == NULL) { - DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name)); - return False; - } - - pstrcpy(passwordprogram, lp_passwd_program()); - pstrcpy(chatsequence, lp_passwd_chat()); - - if (!*chatsequence) { - DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n")); - return (False); - } - - if (!*passwordprogram) { - DEBUG(2, ("chgpasswd: Null password program - no password changing\n")); - return (False); - } - - if (as_root) { - /* The password program *must* contain the user name to work. Fail if not. */ - if (strstr_m(passwordprogram, "%u") == NULL) { - DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \ -the string %%u, and the given string %s does not.\n", passwordprogram )); - return False; - } - } - - pstring_sub(passwordprogram, "%u", name); - /* note that we do NOT substitute the %o and %n in the password program - as this would open up a security hole where the user could use - a new password containing shell escape characters */ - - pstring_sub(chatsequence, "%u", name); - all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring)); - all_string_sub(chatsequence, "%n", newpass, sizeof(pstring)); - return (chat_with_program - (passwordprogram, pass, chatsequence, as_root)); -} - -#else /* ALLOW_CHANGE_PASSWORD */ - -BOOL chgpasswd(const char *name, const struct passwd *pass, - const char *oldpass, const char *newpass, BOOL as_root) -{ - DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name)); - return (False); -} -#endif /* ALLOW_CHANGE_PASSWORD */ - -/*********************************************************** - Code to check the lanman hashed password. -************************************************************/ - -BOOL check_lanman_password(char *user, uchar * pass1, - uchar * pass2, SAM_ACCOUNT **hnd) -{ - uchar unenc_new_pw[16]; - uchar unenc_old_pw[16]; - SAM_ACCOUNT *sampass = NULL; - uint16 acct_ctrl; - const uint8 *lanman_pw; - BOOL ret; - - become_root(); - ret = pdb_getsampwnam(sampass, user); - unbecome_root(); - - if (ret == False) { - DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n")); - pdb_free_sam(&sampass); - return False; - } - - acct_ctrl = pdb_get_acct_ctrl (sampass); - lanman_pw = pdb_get_lanman_passwd (sampass); - - if (acct_ctrl & ACB_DISABLED) { - DEBUG(0,("check_lanman_password: account %s disabled.\n", user)); - pdb_free_sam(&sampass); - return False; - } - - if (lanman_pw == NULL) { - if (acct_ctrl & ACB_PWNOTREQ) { - /* this saves the pointer for the caller */ - *hnd = sampass; - return True; - } else { - DEBUG(0, ("check_lanman_password: no lanman password !\n")); - pdb_free_sam(&sampass); - return False; - } - } - - /* Get the new lanman hash. */ - D_P16(lanman_pw, pass2, unenc_new_pw); - - /* Use this to get the old lanman hash. */ - D_P16(unenc_new_pw, pass1, unenc_old_pw); - - /* Check that the two old passwords match. */ - if (memcmp(lanman_pw, unenc_old_pw, 16)) { - DEBUG(0,("check_lanman_password: old password doesn't match.\n")); - pdb_free_sam(&sampass); - return False; - } - - /* this saves the pointer for the caller */ - *hnd = sampass; - return True; -} - -/*********************************************************** - Code to change the lanman hashed password. - It nulls out the NT hashed password as it will - no longer be valid. - NOTE this function is designed to be called as root. Check the old password - is correct before calling. JRA. -************************************************************/ - -BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar *pass2) -{ - static uchar null_pw[16]; - uchar unenc_new_pw[16]; - BOOL ret; - uint16 acct_ctrl; - const uint8 *pwd; - - if (sampass == NULL) { - DEBUG(0,("change_lanman_password: no smb password entry.\n")); - return False; - } - - acct_ctrl = pdb_get_acct_ctrl(sampass); - pwd = pdb_get_lanman_passwd(sampass); - - if (acct_ctrl & ACB_DISABLED) { - DEBUG(0,("change_lanman_password: account %s disabled.\n", - pdb_get_username(sampass))); - return False; - } - - if (pwd == NULL) { - if (acct_ctrl & ACB_PWNOTREQ) { - uchar no_pw[14]; - memset(no_pw, '\0', 14); - E_P16(no_pw, null_pw); - - /* Get the new lanman hash. */ - D_P16(null_pw, pass2, unenc_new_pw); - } else { - DEBUG(0,("change_lanman_password: no lanman password !\n")); - return False; - } - } else { - /* Get the new lanman hash. */ - D_P16(pwd, pass2, unenc_new_pw); - } - - if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) { - return False; - } - - if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) { - return False; /* We lose the NT hash. Sorry. */ - } - - if (!pdb_set_pass_changed_now (sampass)) { - pdb_free_sam(&sampass); - /* Not quite sure what this one qualifies as, but this will do */ - return False; - } - - /* Now flush the sam_passwd struct to persistent storage */ - ret = pdb_update_sam_account (sampass); - - return ret; -} - -/*********************************************************** - Code to check and change the OEM hashed password. -************************************************************/ - -NTSTATUS pass_oem_change(char *user, - uchar password_encrypted_with_lm_hash[516], - const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], - const uchar old_nt_hash_encrypted[16]) -{ - pstring new_passwd; - SAM_ACCOUNT *sampass = NULL; - NTSTATUS nt_status = check_oem_password(user, password_encrypted_with_lm_hash, - old_lm_hash_encrypted, - password_encrypted_with_nt_hash, - old_nt_hash_encrypted, - &sampass, new_passwd, sizeof(new_passwd)); - - if (!NT_STATUS_IS_OK(nt_status)) - return nt_status; - - /* We've already checked the old password here.... */ - become_root(); - nt_status = change_oem_password(sampass, NULL, new_passwd, True); - unbecome_root(); - - memset(new_passwd, 0, sizeof(new_passwd)); - - pdb_free_sam(&sampass); - - return nt_status; -} - -/*********************************************************** - Decrypt and verify a user password change. - - The 516 byte long buffers are encrypted with the old NT and - old LM passwords, and if the NT passwords are present, both - buffers contain a unicode string. - - After decrypting the buffers, check the password is correct by - matching the old hashed passwords with the passwords in the passdb. - -************************************************************/ - -static NTSTATUS check_oem_password(const char *user, - uchar password_encrypted_with_lm_hash[516], - const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], - const uchar old_nt_hash_encrypted[16], - SAM_ACCOUNT **hnd, char *new_passwd, - int new_passwd_size) -{ - static uchar null_pw[16]; - static uchar null_ntpw[16]; - SAM_ACCOUNT *sampass = NULL; - char *password_encrypted; - const char *encryption_key; - const uint8 *lanman_pw, *nt_pw; - uint16 acct_ctrl; - uint32 new_pw_len; - uchar new_nt_hash[16]; - uchar old_nt_hash_plain[16]; - uchar new_lm_hash[16]; - uchar old_lm_hash_plain[16]; - char no_pw[2]; - BOOL ret; - - BOOL nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted); - BOOL lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted); - - *hnd = NULL; - - pdb_init_sam(&sampass); - - become_root(); - ret = pdb_getsampwnam(sampass, user); - unbecome_root(); - - if (ret == False) { - DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n")); - pdb_free_sam(&sampass); - return NT_STATUS_NO_SUCH_USER; - } - - acct_ctrl = pdb_get_acct_ctrl(sampass); - - if (acct_ctrl & ACB_DISABLED) { - DEBUG(2,("check_lanman_password: account %s disabled.\n", user)); - pdb_free_sam(&sampass); - return NT_STATUS_ACCOUNT_DISABLED; - } - - if (acct_ctrl & ACB_PWNOTREQ && lp_null_passwords()) { - /* construct a null password (in case one is needed */ - no_pw[0] = 0; - no_pw[1] = 0; - nt_lm_owf_gen(no_pw, null_ntpw, null_pw); - lanman_pw = null_pw; - nt_pw = null_pw; - - } else { - /* save pointers to passwords so we don't have to keep looking them up */ - if (lp_lanman_auth()) { - lanman_pw = pdb_get_lanman_passwd(sampass); - } else { - lanman_pw = NULL; - } - nt_pw = pdb_get_nt_passwd(sampass); - } - - if (nt_pw && nt_pass_set) { - /* IDEAL Case: passwords are in unicode, and we can - * read use the password encrypted with the NT hash - */ - password_encrypted = password_encrypted_with_nt_hash; - encryption_key = nt_pw; - } else if (lanman_pw && lm_pass_set) { - /* password may still be in unicode, but use LM hash version */ - password_encrypted = password_encrypted_with_lm_hash; - encryption_key = lanman_pw; - } else if (nt_pass_set) { - DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", - user)); - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } else if (lm_pass_set) { - DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", - user)); - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } else { - DEBUG(1, ("password change requested for user %s, but no password supplied!\n", - user)); - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } - - /* - * Decrypt the password with the key - */ - SamOEMhash( password_encrypted, encryption_key, 516); - - if ( !decode_pw_buffer(password_encrypted, new_passwd, new_passwd_size, &new_pw_len, - nt_pass_set ? STR_UNICODE : STR_ASCII)) { - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } - - /* - * To ensure we got the correct new password, hash it and - * use it as a key to test the passed old password. - */ - - if (nt_pass_set) { - /* NT passwords, verify the NT hash. */ - - /* Calculate the MD4 hash (NT compatible) of the password */ - memset(new_nt_hash, '\0', 16); - E_md4hash(new_passwd, new_nt_hash); - - if (nt_pw) { - /* - * Now use new_nt_hash as the key to see if the old - * password matches. - */ - D_P16(new_nt_hash, old_nt_hash_encrypted, old_nt_hash_plain); - - if (memcmp(nt_pw, old_nt_hash_plain, 16)) { - DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } - - /* We could check the LM password here, but there is - * little point, we already know the password is - * correct, and the LM password might not even be - * present. */ - - /* Further, LM hash generation algorithms - * differ with charset, so we could - * incorrectly fail a perfectly valid password - * change */ -#ifdef DEBUG_PASSWORD - DEBUG(100, - ("check_oem_password: password %s ok\n", new_passwd)); -#endif - *hnd = sampass; - return NT_STATUS_OK; - } - - if (lanman_pw) { - /* - * Now use new_nt_hash as the key to see if the old - * LM password matches. - */ - D_P16(new_nt_hash, old_lm_hash_encrypted, old_lm_hash_plain); - - if (memcmp(lanman_pw, old_lm_hash_plain, 16)) { - DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } -#ifdef DEBUG_PASSWORD - DEBUG(100, - ("check_oem_password: password %s ok\n", new_passwd)); -#endif - *hnd = sampass; - return NT_STATUS_OK; - } - } - - if (lanman_pw && lm_pass_set) { - - E_deshash(new_passwd, new_lm_hash); - - /* - * Now use new_lm_hash as the key to see if the old - * password matches. - */ - D_P16(new_lm_hash, old_lm_hash_encrypted, old_lm_hash_plain); - - if (memcmp(lanman_pw, old_lm_hash_plain, 16)) { - DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; - } - -#ifdef DEBUG_PASSWORD - DEBUG(100, - ("check_oem_password: password %s ok\n", new_passwd)); -#endif - *hnd = sampass; - return NT_STATUS_OK; - } - - /* should not be reached */ - pdb_free_sam(&sampass); - return NT_STATUS_WRONG_PASSWORD; -} - -/*********************************************************** - Code to change the oem password. Changes both the lanman - and NT hashes. Old_passwd is almost always NULL. - NOTE this function is designed to be called as root. Check the old password - is correct before calling. JRA. -************************************************************/ - -NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root) -{ - struct passwd *pass; - - BOOL ret; - uint32 min_len; - - if (time(NULL) < pdb_get_pass_can_change_time(hnd)) { - DEBUG(1, ("user %s cannot change password now, must wait until %s\n", - pdb_get_username(hnd), http_timestring(pdb_get_pass_can_change_time(hnd)))); - return NT_STATUS_PASSWORD_RESTRICTION; - } - - if (account_policy_get(AP_MIN_PASSWORD_LEN, &min_len) && (strlen(new_passwd) < min_len)) { - DEBUG(1, ("user %s cannot change password - password too short\n", - pdb_get_username(hnd))); - DEBUGADD(1, (" account policy min password len = %d\n", min_len)); - return NT_STATUS_PASSWORD_RESTRICTION; -/* return NT_STATUS_PWD_TOO_SHORT; */ - } - - /* Take the passed information and test it for minimum criteria */ - /* Minimum password length */ - if (strlen(new_passwd) < lp_min_passwd_length()) { - /* too short, must be at least MINPASSWDLENGTH */ - DEBUG(1, ("Password Change: user %s, New password is shorter than minimum password length = %d\n", - pdb_get_username(hnd), lp_min_passwd_length())); - return NT_STATUS_PASSWORD_RESTRICTION; -/* return NT_STATUS_PWD_TOO_SHORT; */ - } - - pass = Get_Pwnam(pdb_get_username(hnd)); - if (!pass) { - DEBUG(1, ("check_oem_password: Username does not exist in system !?!\n")); - } - -#ifdef HAVE_WORKING_CRACKLIB - if (pass) { - /* if we can, become the user to overcome internal cracklib sillyness */ - if (!push_sec_ctx()) - return NT_STATUS_UNSUCCESSFUL; - - set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL, NULL); - set_re_uid(); - } - - if (lp_use_cracklib()) { - const char *crack_check_reason; - DEBUG(4, ("change_oem_password: Checking password for user [%s]" - " against cracklib. \n", pdb_get_username(hnd))); - DEBUGADD(4, ("If this is your last message, then something is " - "wrong with cracklib, it might be missing it's " - "dictionaries at %s\n", - CRACKLIB_DICTPATH)); - dbgflush(); - - crack_check_reason = FascistCheck(new_passwd, (char *)CRACKLIB_DICTPATH); - if (crack_check_reason) { - DEBUG(1, ("Password Change: user [%s], " - "New password failed cracklib test - %s\n", - pdb_get_username(hnd), crack_check_reason)); - - /* get back to where we should be */ - if (pass) - pop_sec_ctx(); - return NT_STATUS_PASSWORD_RESTRICTION; - } - } - - if (pass) - pop_sec_ctx(); -#endif - - /* - * If unix password sync was requested, attempt to change - * the /etc/passwd database first. Return failure if this cannot - * be done. - * - * This occurs before the oem change, because we don't want to - * update it if chgpasswd failed. - * - * Conditional on lp_unix_password_sync() because we don't want - * to touch the unix db unless we have admin permission. - */ - - if(lp_unix_password_sync() && - !chgpasswd(pdb_get_username(hnd), pass, old_passwd, new_passwd, as_root)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (!pdb_set_plaintext_passwd (hnd, new_passwd)) { - return NT_STATUS_ACCESS_DENIED; - } - - /* Now write it into the file. */ - ret = pdb_update_sam_account (hnd); - - if (!ret) { - return NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; -} diff --git a/source/smbd/close.c b/source/smbd/close.c deleted file mode 100644 index 0700aeaa0a6..00000000000 --- a/source/smbd/close.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - Unix SMB/CIFS implementation. - file closing - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/**************************************************************************** - Run a file if it is a magic script. -****************************************************************************/ - -static void check_magic(files_struct *fsp,connection_struct *conn) -{ - if (!*lp_magicscript(SNUM(conn))) - return; - - DEBUG(5,("checking magic for %s\n",fsp->fsp_name)); - - { - char *p; - if (!(p = strrchr_m(fsp->fsp_name,'/'))) - p = fsp->fsp_name; - else - p++; - - if (!strequal(lp_magicscript(SNUM(conn)),p)) - return; - } - - { - int ret; - pstring magic_output; - pstring fname; - SMB_STRUCT_STAT st; - int tmp_fd, outfd; - - pstrcpy(fname,fsp->fsp_name); - if (*lp_magicoutput(SNUM(conn))) - pstrcpy(magic_output,lp_magicoutput(SNUM(conn))); - else - slprintf(magic_output,sizeof(fname)-1, "%s.out",fname); - - chmod(fname,0755); - ret = smbrun(fname,&tmp_fd); - DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret)); - unlink(fname); - if (ret != 0 || tmp_fd == -1) { - if (tmp_fd != -1) - close(tmp_fd); - return; - } - outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600); - if (outfd == -1) { - close(tmp_fd); - return; - } - - if (sys_fstat(tmp_fd,&st) == -1) { - close(tmp_fd); - close(outfd); - return; - } - - transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_size); - close(tmp_fd); - close(outfd); - } -} - -/**************************************************************************** - Common code to close a file or a directory. -****************************************************************************/ - -static int close_filestruct(files_struct *fsp) -{ - connection_struct *conn = fsp->conn; - int ret = 0; - - if (fsp->fd != -1) { - if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) - ret = -1; - - delete_write_cache(fsp); - } - - conn->num_files_open--; - SAFE_FREE(fsp->wbmpx_ptr); - - return ret; -} - -/**************************************************************************** - Close a file. - - If normal_close is 1 then this came from a normal SMBclose (or equivalent) - operation otherwise it came as the result of some other operation such as - the closing of the connection. In the latter case printing and - magic scripts are not run. -****************************************************************************/ - -static int close_normal_file(files_struct *fsp, BOOL normal_close) -{ - share_mode_entry *share_entry = NULL; - size_t share_entry_count = 0; - BOOL delete_on_close = False; - connection_struct *conn = fsp->conn; - int err = 0; - int err1 = 0; - - remove_pending_lock_requests_by_fid(fsp); - - /* - * If we're flushing on a close we can get a write - * error here, we must remember this. - */ - - if (close_filestruct(fsp) == -1) - err1 = -1; - - if (fsp->print_file) { - print_fsp_end(fsp, normal_close); - file_free(fsp); - return 0; - } - - /* - * Lock the share entries, and determine if we should delete - * on close. If so delete whilst the lock is still in effect. - * This prevents race conditions with the file being created. JRA. - */ - - lock_share_entry_fsp(fsp); - - if (fsp->delete_on_close) { - - /* - * 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. The last closer will delete the file - * if flag is set. - */ - - NTSTATUS status =set_delete_on_close_over_all(fsp, fsp->delete_on_close); - if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) - DEBUG(0,("close_normal_file: failed to change delete on close flag for file %s\n", - fsp->fsp_name )); - } - - share_entry_count = del_share_mode(fsp, &share_entry); - - DEBUG(10,("close_normal_file: share_entry_count = %lu for file %s\n", - (unsigned long)share_entry_count, fsp->fsp_name )); - - /* - * We delete on close if it's the last open, and the - * delete on close flag was set in the entry we just deleted. - */ - - if ((share_entry_count == 0) && share_entry && - GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) ) - delete_on_close = True; - - SAFE_FREE(share_entry); - - /* - * NT can set delete_on_close of the last open - * 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(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 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 \ -with error %s\n", fsp->fsp_name, strerror(errno) )); - } - process_pending_change_notify_queue((time_t)0); - } - - unlock_share_entry_fsp(fsp); - - if(fsp->oplock_type) - release_file_oplock(fsp); - - locking_close_file(fsp); - - err = fd_close(conn, fsp); - - /* check for magic scripts */ - if (normal_close) { - check_magic(fsp,conn); - } - - /* - * 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) - string_free(&fsp->fsp_name); - - file_free(fsp); - - if (err == -1 || err1 == -1) - return -1; - else - return 0; -} - -/**************************************************************************** - Close a directory opened by an NT SMB call. -****************************************************************************/ - -static int close_directory(files_struct *fsp, BOOL normal_close) -{ - remove_pending_change_notify_requests_by_fid(fsp); - - /* - * NT can set delete_on_close of the last open - * reference to a directory also. - */ - - if (normal_close && fsp->directory_delete_on_close) { - BOOL ok = rmdir_internals(fsp->conn, fsp->fsp_name); - DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n", - fsp->fsp_name, ok ? "succeeded" : "failed" )); - - /* - * Ensure we remove any change notify requests that would - * now fail as the directory has been deleted. - */ - - if(ok) - remove_pending_change_notify_requests_by_filename(fsp); - process_pending_change_notify_queue((time_t)0); - } - - /* - * Do the code common to files and directories. - */ - close_filestruct(fsp); - - if (fsp->fsp_name) - string_free(&fsp->fsp_name); - - file_free(fsp); - return 0; -} - -/**************************************************************************** - Close a 'stat file' opened internally. -****************************************************************************/ - -static int close_stat(files_struct *fsp) -{ - /* - * Do the code common to files and directories. - */ - close_filestruct(fsp); - - if (fsp->fsp_name) - string_free(&fsp->fsp_name); - - file_free(fsp); - return 0; -} - -/**************************************************************************** - Close a files_struct. -****************************************************************************/ - -int close_file(files_struct *fsp, BOOL normal_close) -{ - if(fsp->is_directory) - return close_directory(fsp, normal_close); - else if (fsp->is_stat) - return close_stat(fsp); - else - return close_normal_file(fsp, normal_close); -} diff --git a/source/smbd/conn.c b/source/smbd/conn.c deleted file mode 100644 index 0805f8e6902..00000000000 --- a/source/smbd/conn.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Manage connections_struct structures - Copyright (C) Andrew Tridgell 1998 - Copyright (C) Alexander Bokovoy 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The - * maximum size of the bitmap is the largest positive integer, but you will hit - * the "max connections" limit, looong before that. - */ -#define BITMAP_BLOCK_SZ 128 - -static connection_struct *Connections; - -/* number of open connections */ -static struct bitmap *bmap; -static int num_open; - -/**************************************************************************** -init the conn structures -****************************************************************************/ -void conn_init(void) -{ - bmap = bitmap_allocate(BITMAP_BLOCK_SZ); -} - -/**************************************************************************** -return the number of open connections -****************************************************************************/ -int conn_num_open(void) -{ - return num_open; -} - - -/**************************************************************************** -check if a snum is in use -****************************************************************************/ -BOOL conn_snum_used(int snum) -{ - connection_struct *conn; - for (conn=Connections;conn;conn=conn->next) { - if (conn->service == snum) { - return(True); - } - } - return(False); -} - - -/**************************************************************************** -find a conn given a cnum -****************************************************************************/ -connection_struct *conn_find(unsigned cnum) -{ - int count=0; - connection_struct *conn; - - for (conn=Connections;conn;conn=conn->next,count++) { - if (conn->cnum == cnum) { - if (count > 10) { - DLIST_PROMOTE(Connections, conn); - } - return conn; - } - } - - return NULL; -} - - -/**************************************************************************** - find first available connection slot, starting from a random position. -The randomisation stops problems with the server dieing and clients -thinking the server is still available. -****************************************************************************/ -connection_struct *conn_new(void) -{ - TALLOC_CTX *mem_ctx; - connection_struct *conn; - int i; - int find_offset = 1; - -find_again: - i = bitmap_find(bmap, find_offset); - - if (i == -1) { - /* Expand the connections bitmap. */ - int oldsz = bmap->n; - int newsz = bmap->n + BITMAP_BLOCK_SZ; - struct bitmap * nbmap; - - if (newsz <= 0) { - /* Integer wrap. */ - DEBUG(0,("ERROR! Out of connection structures\n")); - return NULL; - } - - DEBUG(4,("resizing connections bitmap from %d to %d\n", - oldsz, newsz)); - - nbmap = bitmap_allocate(newsz); - - bitmap_copy(nbmap, bmap); - bitmap_free(bmap); - - bmap = nbmap; - find_offset = oldsz; /* Start next search in the new portion. */ - - goto find_again; - } - - if ((mem_ctx=talloc_init("connection_struct"))==NULL) { - DEBUG(0,("talloc_init(connection_struct) failed!\n")); - return NULL; - } - - if ((conn=(connection_struct *)talloc_zero(mem_ctx, sizeof(*conn)))==NULL) { - DEBUG(0,("talloc_zero() failed!\n")); - return NULL; - } - conn->mem_ctx = mem_ctx; - conn->cnum = i; - - bitmap_set(bmap, i); - - num_open++; - - string_set(&conn->user,""); - string_set(&conn->dirpath,""); - string_set(&conn->connectpath,""); - string_set(&conn->origpath,""); - - DLIST_ADD(Connections, conn); - - return conn; -} - -/**************************************************************************** -close all conn structures -****************************************************************************/ -void conn_close_all(void) -{ - connection_struct *conn, *next; - for (conn=Connections;conn;conn=next) { - next=conn->next; - close_cnum(conn, conn->vuid); - } -} - -/**************************************************************************** - Idle inactive connections. -****************************************************************************/ - -BOOL conn_idle_all(time_t t, int deadtime) -{ - pipes_struct *plist = NULL; - BOOL allidle = True; - connection_struct *conn, *next; - - for (conn=Connections;conn;conn=next) { - next=conn->next; - /* close dirptrs on connections that are idle */ - if ((t-conn->lastused) > DPTR_IDLE_TIMEOUT) - dptr_idlecnum(conn); - - if (conn->num_files_open > 0 || - (t-conn->lastused)<deadtime) - allidle = False; - } - - /* - * Check all pipes for any open handles. We cannot - * idle with a handle open. - */ - - for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist)) - if (plist->pipe_handles && plist->pipe_handles->count) - allidle = False; - - return allidle; -} - -/**************************************************************************** - Clear a vuid out of the validity cache, and as the 'owner' of a connection. -****************************************************************************/ - -void conn_clear_vuid_cache(uint16 vuid) -{ - connection_struct *conn; - unsigned int i; - - for (conn=Connections;conn;conn=conn->next) { - if (conn->vuid == vuid) { - conn->vuid = UID_FIELD_INVALID; - } - - for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) { - if (conn->vuid_cache.array[i].vuid == vuid) { - struct vuid_cache_entry *ent = &conn->vuid_cache.array[i]; - ent->vuid = UID_FIELD_INVALID; - ent->read_only = False; - ent->admin_user = False; - } - } - } -} - -/**************************************************************************** - Free a conn structure. -****************************************************************************/ - -void conn_free(connection_struct *conn) -{ - vfs_handle_struct *handle = NULL, *thandle = NULL; - TALLOC_CTX *mem_ctx = NULL; - - /* Free vfs_connection_struct */ - handle = conn->vfs_handles; - while(handle) { - DLIST_REMOVE(conn->vfs_handles, handle); - thandle = handle->next; - if (handle->free_data) - handle->free_data(&handle->data); - handle = thandle; - } - - DLIST_REMOVE(Connections, conn); - - if (conn->ngroups && conn->groups) { - SAFE_FREE(conn->groups); - conn->ngroups = 0; - } - - if (conn->nt_user_token) { - delete_nt_token(&(conn->nt_user_token)); - } - - if (conn->privs) { - destroy_privilege(&(conn->privs)); - } - - free_namearray(conn->veto_list); - free_namearray(conn->hide_list); - free_namearray(conn->veto_oplock_list); - - string_free(&conn->user); - string_free(&conn->dirpath); - string_free(&conn->connectpath); - string_free(&conn->origpath); - - bitmap_clear(bmap, conn->cnum); - num_open--; - - mem_ctx = conn->mem_ctx; - ZERO_STRUCTP(conn); - talloc_destroy(mem_ctx); -} - - -/**************************************************************************** -receive a smbcontrol message to forcibly unmount a share -the message contains just a share name and all instances of that -share are unmounted -the special sharename '*' forces unmount of all shares -****************************************************************************/ -void msg_force_tdis(int msg_type, pid_t pid, void *buf, size_t len) -{ - connection_struct *conn, *next; - fstring sharename; - - fstrcpy(sharename, buf); - - if (strcmp(sharename, "*") == 0) { - DEBUG(1,("Forcing close of all shares\n")); - conn_close_all(); - return; - } - - for (conn=Connections;conn;conn=next) { - next=conn->next; - if (strequal(lp_servicename(conn->service), sharename)) { - DEBUG(1,("Forcing close of share %s cnum=%d\n", - sharename, conn->cnum)); - close_cnum(conn, (uint16)-1); - } - } -} diff --git a/source/smbd/connection.c b/source/smbd/connection.c deleted file mode 100644 index a9ab1424615..00000000000 --- a/source/smbd/connection.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - Unix SMB/CIFS implementation. - connection claim routines - Copyright (C) Andrew Tridgell 1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -static TDB_CONTEXT *tdb; - -/**************************************************************************** - Return the connection tdb context (used for message send all). -****************************************************************************/ - -TDB_CONTEXT *conn_tdb_ctx(void) -{ - if (!tdb) - tdb = tdb_open_ex(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644, smbd_tdb_log); - - return tdb; -} - -static void make_conn_key(connection_struct *conn, const char *name, TDB_DATA *pkbuf, struct connections_key *pkey) -{ - ZERO_STRUCTP(pkey); - pkey->pid = sys_getpid(); - pkey->cnum = conn?conn->cnum:-1; - fstrcpy(pkey->name, name); -#ifdef DEVELOPER - /* valgrind fixer... */ - { - size_t sl = strlen(pkey->name); - if (sizeof(fstring)-sl) - memset(&pkey->name[sl], '\0', sizeof(fstring)-sl); - } -#endif - - pkbuf->dptr = (char *)pkey; - pkbuf->dsize = sizeof(*pkey); -} - -/**************************************************************************** - Delete a connection record. -****************************************************************************/ - -BOOL yield_connection(connection_struct *conn, const char *name) -{ - struct connections_key key; - TDB_DATA kbuf; - - if (!tdb) - return False; - - DEBUG(3,("Yielding connection to %s\n",name)); - - make_conn_key(conn, name, &kbuf, &key); - - if (tdb_delete(tdb, kbuf) != 0) { - 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); - } - - return(True); -} - -struct count_stat { - pid_t mypid; - int curr_connections; - char *name; - BOOL Clear; -}; - -/**************************************************************************** - Count the entries belonging to a service in the connection db. -****************************************************************************/ - -static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *udp) -{ - struct connections_data crec; - struct count_stat *cs = (struct count_stat *)udp; - - if (dbuf.dsize != sizeof(crec)) - return 0; - - memcpy(&crec, dbuf.dptr, sizeof(crec)); - - if (crec.cnum == -1) - return 0; - - /* If the pid was not found delete the entry from connections.tdb */ - - if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) { - DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n", - (unsigned int)crec.pid, crec.cnum, crec.name)); - if (tdb_delete(the_tdb, kbuf) != 0) - DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) )); - return 0; - } - - if (strequal(crec.name, cs->name)) - cs->curr_connections++; - - return 0; -} - -/**************************************************************************** - Claim an entry in the connections database. -****************************************************************************/ - -BOOL claim_connection(connection_struct *conn, const char *name,int max_connections,BOOL Clear, uint32 msg_flags) -{ - struct connections_key key; - struct connections_data crec; - TDB_DATA kbuf, dbuf; - - if (!tdb) - tdb = tdb_open_ex(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644, smbd_tdb_log); - - if (!tdb) - return False; - - /* - * Enforce the max connections parameter. - */ - - if (max_connections > 0) { - struct count_stat cs; - - cs.mypid = sys_getpid(); - cs.curr_connections = 0; - cs.name = lp_servicename(SNUM(conn)); - cs.Clear = Clear; - - /* - * This has a race condition, but locking the chain before hand is worse - * as it leads to deadlock. - */ - - if (tdb_traverse(tdb, count_fn, &cs) == -1) { - DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n", - tdb_errorstr(tdb) )); - return False; - } - - if (cs.curr_connections >= max_connections) { - DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n", - max_connections, name )); - return False; - } - } - - DEBUG(5,("claiming %s %d\n",name,max_connections)); - - make_conn_key(conn, name, &kbuf, &key); - - /* fill in the crec */ - ZERO_STRUCT(crec); - crec.magic = 0x280267; - crec.pid = sys_getpid(); - crec.cnum = conn?conn->cnum:-1; - if (conn) { - crec.uid = conn->uid; - crec.gid = conn->gid; - safe_strcpy(crec.name, - lp_servicename(SNUM(conn)),sizeof(crec.name)-1); - } - crec.start = time(NULL); - crec.bcast_msg_flags = msg_flags; - - safe_strcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1); - safe_strcpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1); - - dbuf.dptr = (char *)&crec; - dbuf.dsize = sizeof(crec); - - if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { - DEBUG(0,("claim_connection: tdb_store failed with error %s.\n", - tdb_errorstr(tdb) )); - return False; - } - - return True; -} - -BOOL register_message_flags(BOOL doreg, uint32 msg_flags) -{ - struct connections_key key; - struct connections_data *pcrec; - TDB_DATA kbuf, dbuf; - - if (!tdb) - return False; - - DEBUG(10,("register_message_flags: %s flags 0x%x\n", - doreg ? "adding" : "removing", - (unsigned int)msg_flags )); - - make_conn_key(NULL, "", &kbuf, &key); - - dbuf = tdb_fetch(tdb, kbuf); - if (!dbuf.dptr) { - DEBUG(0,("register_message_flags: tdb_fetch failed\n")); - return False; - } - - pcrec = (struct connections_data *)dbuf.dptr; - pcrec->bcast_msg_flags = msg_flags; - if (doreg) - pcrec->bcast_msg_flags |= msg_flags; - else - pcrec->bcast_msg_flags &= ~msg_flags; - - if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { - DEBUG(0,("register_message_flags: tdb_store failed with error %s.\n", - tdb_errorstr(tdb) )); - SAFE_FREE(dbuf.dptr); - return False; - } - - DEBUG(10,("register_message_flags: new flags 0x%x\n", - (unsigned int)pcrec->bcast_msg_flags )); - - SAFE_FREE(dbuf.dptr); - return True; -} diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c deleted file mode 100644 index f93cdf3791e..00000000000 --- a/source/smbd/dfree.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - Unix SMB/CIFS implementation. - functions to calculate the free disk space - Copyright (C) Andrew Tridgell 1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/**************************************************************************** -normalise for DOS usage -****************************************************************************/ -static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) -{ - /* check if the disk is beyond the max disk size */ - SMB_BIG_UINT maxdisksize = lp_maxdisksize(); - if (maxdisksize) { - /* convert to blocks - and don't overflow */ - maxdisksize = ((maxdisksize*1024)/(*bsize))*1024; - if (*dsize > maxdisksize) *dsize = maxdisksize; - if (*dfree > maxdisksize) *dfree = maxdisksize-1; - /* the -1 should stop applications getting div by 0 - errors */ - } - - while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) { - *dfree /= 2; - *dsize /= 2; - *bsize *= 2; - if(small_query) { - /* - * Force max to fit in 16 bit fields. - */ - if (*bsize > (WORDMAX*512)) { - *bsize = (WORDMAX*512); - if (*dsize > WORDMAX) - *dsize = WORDMAX; - if (*dfree > WORDMAX) - *dfree = WORDMAX; - break; - } - } - } -} - - - -/**************************************************************************** - return number of 1K blocks available on a path and total number -****************************************************************************/ - -static SMB_BIG_UINT disk_free(const char *path, BOOL small_query, - SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) -{ - int dfree_retval; - SMB_BIG_UINT dfree_q = 0; - SMB_BIG_UINT bsize_q = 0; - SMB_BIG_UINT dsize_q = 0; - char *dfree_command; - - (*dfree) = (*dsize) = 0; - (*bsize) = 512; - - /* - * If external disk calculation specified, use it. - */ - - dfree_command = lp_dfree_command(); - if (dfree_command && *dfree_command) { - const char *p; - char **lines; - pstring syscmd; - - slprintf(syscmd, sizeof(syscmd)-1, "%s %s", dfree_command, path); - DEBUG (3, ("disk_free: Running command %s\n", syscmd)); - - lines = file_lines_pload(syscmd, NULL); - if (lines) { - char *line = lines[0]; - - DEBUG (3, ("Read input from dfree, \"%s\"\n", line)); - - *dsize = STR_TO_SMB_BIG_UINT(line, &p); - while (p && *p && isspace(*p)) - p++; - if (p && *p) - *dfree = STR_TO_SMB_BIG_UINT(p, &p); - while (p && *p && isspace(*p)) - p++; - if (p && *p) - *bsize = STR_TO_SMB_BIG_UINT(p, NULL); - else - *bsize = 1024; - file_lines_free(lines); - DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n", - (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize)); - - if (!*dsize) - *dsize = 2048; - if (!*dfree) - *dfree = 1024; - } else { - DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n", - syscmd, strerror(errno) )); - sys_fsusage(path, dfree, dsize); - } - } else - sys_fsusage(path, dfree, dsize); - - if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) { - (*bsize) = bsize_q; - (*dfree) = MIN(*dfree,dfree_q); - (*dsize) = MIN(*dsize,dsize_q); - } - - /* FIXME : Any reason for this assumption ? */ - if (*bsize < 256) { - DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize)); - *bsize = 512; - } - - if ((*dsize)<1) { - static int done; - if (!done) { - DEBUG(0,("WARNING: dfree is broken on this system\n")); - done=1; - } - *dsize = 20*1024*1024/(*bsize); - *dfree = MAX(1,*dfree); - } - - disk_norm(small_query,bsize,dfree,dsize); - - if ((*bsize) < 1024) { - dfree_retval = (*dfree)/(1024/(*bsize)); - } else { - dfree_retval = ((*bsize)/1024)*(*dfree); - } - - return(dfree_retval); -} - - -/**************************************************************************** -wrap it to get filenames right -****************************************************************************/ -SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query, - SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) -{ - return disk_free(path,small_query, bsize,dfree,dsize); -} diff --git a/source/smbd/dir.c b/source/smbd/dir.c deleted file mode 100644 index 06ef23ab8cd..00000000000 --- a/source/smbd/dir.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Directory handling routines - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* - This module implements directory related functions for Samba. -*/ - -typedef struct _dptr_struct { - struct _dptr_struct *next, *prev; - int dnum; - uint16 spid; - connection_struct *conn; - void *ptr; - BOOL expect_close; - char *wcard; /* Field only used for trans2_ searches */ - uint16 attr; /* Field only used for trans2_ searches */ - char *path; -} dptr_struct; - -static struct bitmap *dptr_bmap; -static dptr_struct *dirptrs; - -static int dptrs_open = 0; - -#define INVALID_DPTR_KEY (-3) - -/**************************************************************************** - Initialise the dir bitmap. -****************************************************************************/ - -void init_dptrs(void) -{ - static BOOL dptrs_init=False; - - if (dptrs_init) - return; - - dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES); - - if (!dptr_bmap) - exit_server("out of memory in init_dptrs"); - - dptrs_init = True; -} - -/**************************************************************************** - Idle a dptr - the directory is closed but the control info is kept. -****************************************************************************/ - -static void dptr_idle(dptr_struct *dptr) -{ - if (dptr->ptr) { - DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum)); - dptrs_open--; - CloseDir(dptr->ptr); - dptr->ptr = NULL; - } -} - -/**************************************************************************** - Idle the oldest dptr. -****************************************************************************/ - -static void dptr_idleoldest(void) -{ - dptr_struct *dptr; - - /* - * Go to the end of the list. - */ - for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next) - ; - - if(!dptr) { - DEBUG(0,("No dptrs available to idle ?\n")); - return; - } - - /* - * Idle the oldest pointer. - */ - - for(; dptr; dptr = dptr->prev) { - if (dptr->ptr) { - dptr_idle(dptr); - return; - } - } -} - -/**************************************************************************** - Get the dptr_struct for a dir index. -****************************************************************************/ - -static dptr_struct *dptr_get(int key, BOOL forclose) -{ - dptr_struct *dptr; - - for(dptr = dirptrs; dptr; dptr = dptr->next) { - if(dptr->dnum == key) { - if (!forclose && !dptr->ptr) { - if (dptrs_open >= MAX_OPEN_DIRECTORIES) - dptr_idleoldest(); - DEBUG(4,("Reopening dptr key %d\n",key)); - if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True))) - dptrs_open++; - } - DLIST_PROMOTE(dirptrs,dptr); - return dptr; - } - } - return(NULL); -} - -/**************************************************************************** - Get the dptr ptr for a dir index. -****************************************************************************/ - -static void *dptr_ptr(int key) -{ - dptr_struct *dptr = dptr_get(key, False); - - if (dptr) - return(dptr->ptr); - return(NULL); -} - -/**************************************************************************** - Get the dir path for a dir index. -****************************************************************************/ - -char *dptr_path(int key) -{ - dptr_struct *dptr = dptr_get(key, False); - - if (dptr) - return(dptr->path); - return(NULL); -} - -/**************************************************************************** - Get the dir wcard for a dir index (lanman2 specific). -****************************************************************************/ - -char *dptr_wcard(int key) -{ - dptr_struct *dptr = dptr_get(key, False); - - if (dptr) - return(dptr->wcard); - return(NULL); -} - -/**************************************************************************** - Set the dir wcard for a dir index (lanman2 specific). - Returns 0 on ok, 1 on fail. -****************************************************************************/ - -BOOL dptr_set_wcard(int key, char *wcard) -{ - dptr_struct *dptr = dptr_get(key, False); - - if (dptr) { - dptr->wcard = wcard; - return True; - } - return False; -} - -/**************************************************************************** - Set the dir attrib for a dir index (lanman2 specific). - Returns 0 on ok, 1 on fail. -****************************************************************************/ - -BOOL dptr_set_attr(int key, uint16 attr) -{ - dptr_struct *dptr = dptr_get(key, False); - - if (dptr) { - dptr->attr = attr; - return True; - } - return False; -} - -/**************************************************************************** - Get the dir attrib for a dir index (lanman2 specific) -****************************************************************************/ - -uint16 dptr_attr(int key) -{ - dptr_struct *dptr = dptr_get(key, False); - - if (dptr) - return(dptr->attr); - return(0); -} - -/**************************************************************************** - Close a dptr (internal func). -****************************************************************************/ - -static void dptr_close_internal(dptr_struct *dptr) -{ - DEBUG(4,("closing dptr key %d\n",dptr->dnum)); - - DLIST_REMOVE(dirptrs, dptr); - - /* - * Free the dnum in the bitmap. Remember the dnum value is always - * biased by one with respect to the bitmap. - */ - - if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) { - DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n", - dptr->dnum )); - } - - bitmap_clear(dptr_bmap, dptr->dnum - 1); - - if (dptr->ptr) { - CloseDir(dptr->ptr); - dptrs_open--; - } - - /* Lanman 2 specific code */ - SAFE_FREE(dptr->wcard); - string_set(&dptr->path,""); - SAFE_FREE(dptr); -} - -/**************************************************************************** - Close a dptr given a key. -****************************************************************************/ - -void dptr_close(int *key) -{ - dptr_struct *dptr; - - if(*key == INVALID_DPTR_KEY) - return; - - /* OS/2 seems to use -1 to indicate "close all directories" */ - if (*key == -1) { - dptr_struct *next; - for(dptr = dirptrs; dptr; dptr = next) { - next = dptr->next; - dptr_close_internal(dptr); - } - *key = INVALID_DPTR_KEY; - return; - } - - dptr = dptr_get(*key, True); - - if (!dptr) { - DEBUG(0,("Invalid key %d given to dptr_close\n", *key)); - return; - } - - dptr_close_internal(dptr); - - *key = INVALID_DPTR_KEY; -} - -/**************************************************************************** - Close all dptrs for a cnum. -****************************************************************************/ - -void dptr_closecnum(connection_struct *conn) -{ - dptr_struct *dptr, *next; - for(dptr = dirptrs; dptr; dptr = next) { - next = dptr->next; - if (dptr->conn == conn) - dptr_close_internal(dptr); - } -} - -/**************************************************************************** - Idle all dptrs for a cnum. -****************************************************************************/ - -void dptr_idlecnum(connection_struct *conn) -{ - dptr_struct *dptr; - for(dptr = dirptrs; dptr; dptr = dptr->next) { - if (dptr->conn == conn && dptr->ptr) - dptr_idle(dptr); - } -} - -/**************************************************************************** - Close a dptr that matches a given path, only if it matches the spid also. -****************************************************************************/ - -void dptr_closepath(char *path,uint16 spid) -{ - dptr_struct *dptr, *next; - for(dptr = dirptrs; dptr; dptr = next) { - next = dptr->next; - if (spid == dptr->spid && strequal(dptr->path,path)) - dptr_close_internal(dptr); - } -} - -/**************************************************************************** - Start a directory listing. -****************************************************************************/ - -static BOOL start_dir(connection_struct *conn, pstring directory) -{ - const char *dir2; - - DEBUG(5,("start_dir dir=%s\n",directory)); - - if (!check_name(directory,conn)) - return(False); - - /* use a const pointer from here on */ - dir2 = directory; - - if (! *dir2) - dir2 = "."; - - conn->dirptr = OpenDir(conn, directory, True); - if (conn->dirptr) { - dptrs_open++; - string_set(&conn->dirpath,directory); - return(True); - } - - return(False); -} - -/**************************************************************************** - Try and close the oldest handle not marked for - expect close in the hope that the client has - finished with that one. -****************************************************************************/ - -static void dptr_close_oldest(BOOL old) -{ - dptr_struct *dptr; - - /* - * Go to the end of the list. - */ - for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next) - ; - - if(!dptr) { - DEBUG(0,("No old dptrs available to close oldest ?\n")); - return; - } - - /* - * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that - * does not have expect_close set. If 'old' is false, close - * one of the new dnum handles. - */ - - for(; dptr; dptr = dptr->prev) { - if ((old && (dptr->dnum < 256) && !dptr->expect_close) || - (!old && (dptr->dnum > 255))) { - dptr_close_internal(dptr); - return; - } - } -} - -/**************************************************************************** - Create a new dir ptr. If the flag old_handle is true then we must allocate - from the bitmap range 0 - 255 as old SMBsearch directory handles are only - one byte long. If old_handle is false we allocate from the range - 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure - a directory handle is never zero. All the above is folklore taught to - me at Andrew's knee.... :-) :-). JRA. -****************************************************************************/ - -int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid) -{ - dptr_struct *dptr; - - if (!start_dir(conn,path)) - return(-2); /* Code to say use a unix error return code. */ - - if (dptrs_open >= MAX_OPEN_DIRECTORIES) - dptr_idleoldest(); - - dptr = (dptr_struct *)malloc(sizeof(dptr_struct)); - if(!dptr) { - DEBUG(0,("malloc fail in dptr_create.\n")); - return -1; - } - - ZERO_STRUCTP(dptr); - - if(old_handle) { - - /* - * This is an old-style SMBsearch request. Ensure the - * value we return will fit in the range 1-255. - */ - - dptr->dnum = bitmap_find(dptr_bmap, 0); - - if(dptr->dnum == -1 || dptr->dnum > 254) { - - /* - * Try and close the oldest handle not marked for - * expect close in the hope that the client has - * finished with that one. - */ - - dptr_close_oldest(True); - - /* Now try again... */ - dptr->dnum = bitmap_find(dptr_bmap, 0); - if(dptr->dnum == -1 || dptr->dnum > 254) { - DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum)); - SAFE_FREE(dptr); - return -1; - } - } - } else { - - /* - * This is a new-style trans2 request. Allocate from - * a range that will return 256 - MAX_DIRECTORY_HANDLES. - */ - - dptr->dnum = bitmap_find(dptr_bmap, 255); - - if(dptr->dnum == -1 || dptr->dnum < 255) { - - /* - * Try and close the oldest handle close in the hope that - * the client has finished with that one. This will only - * happen in the case of the Win98 client bug where it leaks - * directory handles. - */ - - dptr_close_oldest(False); - - /* Now try again... */ - dptr->dnum = bitmap_find(dptr_bmap, 255); - - if(dptr->dnum == -1 || dptr->dnum < 255) { - DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum)); - SAFE_FREE(dptr); - return -1; - } - } - } - - bitmap_set(dptr_bmap, dptr->dnum); - - dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */ - - dptr->ptr = conn->dirptr; - string_set(&dptr->path,path); - dptr->conn = conn; - dptr->spid = spid; - dptr->expect_close = expect_close; - dptr->wcard = NULL; /* Only used in lanman2 searches */ - dptr->attr = 0; /* Only used in lanman2 searches */ - - DLIST_ADD(dirptrs, dptr); - - DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n", - dptr->dnum,path,expect_close)); - - return(dptr->dnum); -} - -/**************************************************************************** - Fill the 5 byte server reserved dptr field. -****************************************************************************/ - -BOOL dptr_fill(char *buf1,unsigned int key) -{ - unsigned char *buf = (unsigned char *)buf1; - void *p = dptr_ptr(key); - uint32 offset; - if (!p) { - DEBUG(1,("filling null dirptr %d\n",key)); - return(False); - } - offset = TellDir(p); - DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key, - (long)p,(int)offset)); - buf[0] = key; - SIVAL(buf,1,offset | DPTR_MASK); - return(True); -} - -/**************************************************************************** - Fetch the dir ptr and seek it given the 5 byte server field. -****************************************************************************/ - -void *dptr_fetch(char *buf,int *num) -{ - unsigned int key = *(unsigned char *)buf; - void *p = dptr_ptr(key); - uint32 offset; - - if (!p) { - DEBUG(3,("fetched null dirptr %d\n",key)); - return(NULL); - } - *num = key; - offset = IVAL(buf,1)&~DPTR_MASK; - SeekDir(p,offset); - DEBUG(3,("fetching dirptr %d for path %s at offset %d\n", - key,dptr_path(key),offset)); - return(p); -} - -/**************************************************************************** - Fetch the dir ptr. -****************************************************************************/ - -void *dptr_fetch_lanman2(int dptr_num) -{ - void *p = dptr_ptr(dptr_num); - - if (!p) { - DEBUG(3,("fetched null dirptr %d\n",dptr_num)); - return(NULL); - } - DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num))); - return(p); -} - -/**************************************************************************** - Check a filetype for being valid. -****************************************************************************/ - -BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype) -{ - int mask; - - /* Check the "may have" search bits. */ - if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0) - return False; - - /* Check the "must have" bits, which are the may have bits shifted eight */ - /* If must have bit is set, the file/dir can not be returned in search unless the matching - file attribute is set */ - mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */ - if(mask) { - if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */ - return True; - else - return False; - } - - return True; -} - -static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask) -{ - mangle_map(filename,True,False,SNUM(conn)); - return mask_match(filename,mask,False); -} - -/**************************************************************************** - Get an 8.3 directory entry. -****************************************************************************/ - -BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname, - SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend) -{ - const char *dname; - BOOL found = False; - SMB_STRUCT_STAT sbuf; - pstring path; - pstring pathreal; - BOOL isrootdir; - pstring filename; - BOOL needslash; - - *path = *pathreal = *filename = 0; - - isrootdir = (strequal(conn->dirpath,"./") || - strequal(conn->dirpath,".") || - strequal(conn->dirpath,"/")); - - needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); - - if (!conn->dirptr) - return(False); - - while (!found) { - dname = ReadDirName(conn->dirptr); - - DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n", - (long)conn->dirptr,TellDir(conn->dirptr))); - - if (dname == NULL) - return(False); - - pstrcpy(filename,dname); - - /* notice the special *.* handling. This appears to be the only difference - between the wildcard handling in this routine and in the trans2 routines. - see masktest for a demo - */ - if ((strcmp(mask,"*.*") == 0) || - mask_match(filename,mask,False) || - mangle_mask_match(conn,filename,mask)) { - if (isrootdir && (strequal(filename,"..") || strequal(filename,"."))) - continue; - - if (!mangle_is_8_3(filename, False)) - mangle_map(filename,True,False,SNUM(conn)); - - pstrcpy(fname,filename); - *path = 0; - pstrcpy(path,conn->dirpath); - if(needslash) - pstrcat(path,"/"); - pstrcpy(pathreal,path); - pstrcat(path,fname); - pstrcat(pathreal,dname); - if (SMB_VFS_STAT(conn, pathreal, &sbuf) != 0) { - DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) )); - continue; - } - - *mode = dos_mode(conn,pathreal,&sbuf); - - if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) { - DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype)); - continue; - } - - *size = sbuf.st_size; - *date = sbuf.st_mtime; - - DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname)); - - found = True; - } - } - - return(found); -} - -typedef struct { - int pos; - int numentries; - int mallocsize; - char *data; - char *current; -} Dir; - -/******************************************************************* - 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, SMB_STRUCT_STAT *pst) -{ - extern struct current_user current_user; - SEC_DESC *psd = NULL; - size_t sd_size; - files_struct *fsp; - int smb_action; - NTSTATUS status; - uint32 access_granted; - - /* - * If user is a member of the Admin group - * we never hide files from them. - */ - - if (conn->admin_user) - return True; - - /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) - return False; - - /* Pseudo-open the file (note - no fd's created). */ - - if(S_ISDIR(pst->st_mode)) - fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - &smb_action); - else - fsp = open_file_stat(conn, name, pst); - - if (!fsp) - return False; - - /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, - (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &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); -} - -/******************************************************************* - Check to see if a user can write a file (and only files, we do not - check dirs on this one). This is only approximate, - it is used as part of the "hide unwriteable" option. Don't - use it for anything security sensitive. -********************************************************************/ - -static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) -{ - extern struct current_user current_user; - SEC_DESC *psd = NULL; - size_t sd_size; - files_struct *fsp; - int smb_action; - int access_mode; - NTSTATUS status; - uint32 access_granted; - - /* - * If user is a member of the Admin group - * we never hide files from them. - */ - - if (conn->admin_user) - return True; - - /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) - return False; - - /* Pseudo-open the file (note - no fd's created). */ - - if(S_ISDIR(pst->st_mode)) - return True; - else - fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action); - - if (!fsp) - return False; - - /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, - (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); - close_file(fsp, False); - - /* No access if SD get failed. */ - if (!sd_size) - return False; - - return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA, - &access_granted, &status); -} - -/******************************************************************* - Is a file a "special" type ? -********************************************************************/ - -static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) -{ - /* - * If user is a member of the Admin group - * we never hide files from them. - */ - - if (conn->admin_user) - return False; - - /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) - return True; - - if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode)) - return False; - - return True; -} - -/******************************************************************* - Open a directory. -********************************************************************/ - -void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto) -{ - Dir *dirp; - const char *n; - DIR *p = SMB_VFS_OPENDIR(conn,name); - int used=0; - - if (!p) - return(NULL); - dirp = (Dir *)malloc(sizeof(Dir)); - if (!dirp) { - DEBUG(0,("Out of memory in OpenDir\n")); - SMB_VFS_CLOSEDIR(conn,p); - return(NULL); - } - dirp->pos = dirp->numentries = dirp->mallocsize = 0; - dirp->data = dirp->current = NULL; - - while (True) { - int l; - BOOL normal_entry = True; - SMB_STRUCT_STAT st; - char *entry = NULL; - - if (used == 0) { - n = "."; - normal_entry = False; - } else if (used == 2) { - n = ".."; - normal_entry = False; - } else { - n = vfs_readdirname(conn, p); - if (n == NULL) - break; - if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0)) - continue; - normal_entry = True; - } - - ZERO_STRUCT(st); - l = strlen(n)+1; - - /* If it's a vetoed file, pretend it doesn't even exist */ - if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n)) - continue; - - /* Honour _hide unreadable_ option */ - if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) { - int ret=0; - - if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { - ret = user_can_read_file(conn, entry, &st); - } - if (!ret) { - SAFE_FREE(entry); - continue; - } - } - - /* Honour _hide unwriteable_ option */ - if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) { - int ret=0; - - if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { - ret = user_can_write_file(conn, entry, &st); - } - if (!ret) { - SAFE_FREE(entry); - continue; - } - } - - /* Honour _hide_special_ option */ - if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) { - int ret=0; - - if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { - ret = file_is_special(conn, entry, &st); - } - if (ret) { - SAFE_FREE(entry); - continue; - } - } - - SAFE_FREE(entry); - - if (used + l > dirp->mallocsize) { - int s = MAX(used+l,used+2000); - char *r; - r = (char *)Realloc(dirp->data,s); - if (!r) { - DEBUG(0,("Out of memory in OpenDir\n")); - break; - } - dirp->data = r; - dirp->mallocsize = s; - dirp->current = dirp->data; - } - - safe_strcpy_base(dirp->data+used,n, dirp->data, dirp->mallocsize); - used += l; - dirp->numentries++; - } - - SMB_VFS_CLOSEDIR(conn,p); - return((void *)dirp); -} - - -/******************************************************************* - Close a directory. -********************************************************************/ - -void CloseDir(void *p) -{ - if (!p) - return; - SAFE_FREE(((Dir *)p)->data); - SAFE_FREE(p); -} - -/******************************************************************* - Read from a directory. -********************************************************************/ - -const char *ReadDirName(void *p) -{ - char *ret; - Dir *dirp = (Dir *)p; - - if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) - return(NULL); - - ret = dirp->current; - dirp->current = skip_string(dirp->current,1); - dirp->pos++; - - return(ret); -} - -/******************************************************************* - Seek a dir. -********************************************************************/ - -BOOL SeekDir(void *p,int pos) -{ - Dir *dirp = (Dir *)p; - - if (!dirp) - return(False); - - if (pos < dirp->pos) { - dirp->current = dirp->data; - dirp->pos = 0; - } - - while (dirp->pos < pos && ReadDirName(p)) - ; - - return (dirp->pos == pos); -} - -/******************************************************************* - Tell a dir position. -********************************************************************/ - -int TellDir(void *p) -{ - Dir *dirp = (Dir *)p; - - if (!dirp) - return(-1); - - return(dirp->pos); -} - -/******************************************************************************* - This section manages a global directory cache. - (It should probably be split into a separate module. crh) -********************************************************************************/ - -typedef struct { - ubi_dlNode node; - char *path; - char *name; - char *dname; - int snum; -} dir_cache_entry; - -static ubi_dlNewList( dir_cache ); - -/***************************************************************************** - Add an entry to the directory cache. - Input: path - - name - - dname - - snum - - Output: None. -*****************************************************************************/ - -void DirCacheAdd( const char *path, const char *name, const char *dname, int snum ) -{ - int pathlen; - int namelen; - dir_cache_entry *entry; - - /* - * Allocate the structure & string space in one go so that it can be freed - * in one call to free(). - */ - pathlen = strlen(path) + 1; /* Bytes required to store path (with nul). */ - namelen = strlen(name) + 1; /* Bytes required to store name (with nul). */ - entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry ) - + pathlen - + namelen - + strlen( dname ) +1 ); - if( NULL == entry ) /* Not adding to the cache is not fatal, */ - return; /* so just return as if nothing happened. */ - - /* Set pointers correctly and load values. */ - entry->path = memcpy( (char *)&entry[1], path, strlen(path)+1 ); - entry->name = memcpy( &(entry->path[pathlen]), name, strlen(name)+1 ); - entry->dname = memcpy( &(entry->name[namelen]), dname, strlen(dname)+1 ); - entry->snum = snum; - - /* Add the new entry to the linked list. */ - (void)ubi_dlAddHead( dir_cache, entry ); - DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) ); - - /* Free excess cache entries. */ - while( DIRCACHESIZE < dir_cache->count ) - safe_free( ubi_dlRemTail( dir_cache ) ); -} - -/***************************************************************************** - Search for an entry to the directory cache. - Input: path - - name - - snum - - Output: The dname string of the located entry, or NULL if the entry was - not found. - - Notes: This uses a linear search, which is is okay because of - the small size of the cache. Use a splay tree or hash - for large caches. -*****************************************************************************/ - -char *DirCacheCheck( const char *path, const char *name, int snum ) -{ - dir_cache_entry *entry; - - for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); - NULL != entry; - entry = (dir_cache_entry *)ubi_dlNext( entry ) ) { - if( entry->snum == snum - && entry->name && 0 == strcmp( name, entry->name ) - && entry->path && 0 == strcmp( path, entry->path ) ) { - DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname)); - return( entry->dname ); - } - } - - return(NULL); -} - -/***************************************************************************** - Remove all cache entries which have an snum that matches the input. - Input: snum - - Output: None. -*****************************************************************************/ - -void DirCacheFlush(int snum) -{ - dir_cache_entry *entry; - ubi_dlNodePtr next; - - for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); - NULL != entry; ) { - next = ubi_dlNext( entry ); - if( entry->snum == snum ) - safe_free( ubi_dlRemThis( dir_cache, entry ) ); - entry = (dir_cache_entry *)next; - } -} diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c deleted file mode 100644 index d7dc63bb2fd..00000000000 --- a/source/smbd/dosmode.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - Unix SMB/CIFS implementation. - dos mode handling functions - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/**************************************************************************** - Change a dos mode to a unix mode. - Base permission for files: - if inheriting - apply read/write bits from parent directory. - else - everybody gets read bit set - dos readonly is represented in unix by removing everyone's write bit - dos archive is represented in unix by the user's execute bit - dos system is represented in unix by the group's execute bit - dos hidden is represented in unix by the other's execute bit - if !inheriting { - Then apply create mask, - then add force bits. - } - Base permission for directories: - dos directory is represented in unix by unix's dir bit and the exec bit - if !inheriting { - Then apply create mask, - then add force bits. - } -****************************************************************************/ - -mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname) -{ - mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); - mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */ - - if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) { - result &= ~(S_IWUSR | S_IWGRP | S_IWOTH); - } - - if (fname && lp_inherit_perms(SNUM(conn))) { - char *dname; - SMB_STRUCT_STAT sbuf; - - dname = parent_dirname(fname); - DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname)); - if (SMB_VFS_STAT(conn,dname,&sbuf) != 0) { - DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno))); - return(0); /* *** shouldn't happen! *** */ - } - - /* Save for later - but explicitly remove setuid bit for safety. */ - dir_mode = sbuf.st_mode & ~S_ISUID; - DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode)); - /* Clear "result" */ - result = 0; - } - - if (IS_DOS_DIR(dosmode)) { - /* We never make directories read only for the owner as under DOS a user - can always create a file in a read-only directory. */ - result |= (S_IFDIR | S_IWUSR); - - if (dir_mode) { - /* Inherit mode of parent directory. */ - result |= dir_mode; - } else { - /* Provisionally add all 'x' bits */ - result |= (S_IXUSR | S_IXGRP | S_IXOTH); - - /* Apply directory mask */ - result &= lp_dir_mask(SNUM(conn)); - /* Add in force bits */ - result |= lp_force_dir_mode(SNUM(conn)); - } - } else { - if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode)) - result |= S_IXUSR; - - if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode)) - result |= S_IXGRP; - - if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode)) - result |= S_IXOTH; - - if (dir_mode) { - /* Inherit 666 component of parent directory mode */ - result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); - } else { - /* Apply mode mask */ - result &= lp_create_mask(SNUM(conn)); - /* Add in force bits */ - result |= lp_force_create_mode(SNUM(conn)); - } - } - - DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result )); - return(result); -} - -/**************************************************************************** - Change a unix mode to a dos mode. -****************************************************************************/ - -uint32 dos_mode_from_sbuf(connection_struct *conn, SMB_STRUCT_STAT *sbuf) -{ - int result = 0; - - if ((sbuf->st_mode & S_IWUSR) == 0) - result |= aRONLY; - - if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) - result |= aARCH; - - if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) - result |= aSYSTEM; - - if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) - result |= aHIDDEN; - - if (S_ISDIR(sbuf->st_mode)) - result = aDIR | (result & aRONLY); - -#if defined (HAVE_STAT_ST_BLOCKS) && defined (HAVE_STAT_ST_BLKSIZE) - if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)sbuf->st_blksize) { - result |= FILE_ATTRIBUTE_SPARSE; - } -#endif - -#ifdef S_ISLNK -#if LINKS_READ_ONLY - if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) - result |= aRONLY; -#endif -#endif - - DEBUG(8,("dos_mode_from_sbuf returning ")); - - if (result & aHIDDEN) DEBUG(8, ("h")); - if (result & aRONLY ) DEBUG(8, ("r")); - if (result & aSYSTEM) DEBUG(8, ("s")); - if (result & aDIR ) DEBUG(8, ("d")); - if (result & aARCH ) DEBUG(8, ("a")); - - DEBUG(8,("\n")); - return result; -} - -/**************************************************************************** - Get DOS attributes from an EA. -****************************************************************************/ - -static BOOL get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr) -{ - ssize_t sizeret; - fstring attrstr; - unsigned int dosattr; - - if (!lp_store_dos_attributes(SNUM(conn))) { - return False; - } - - *pattr = 0; - - sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr)); - if (sizeret == -1) { -#if defined(ENOTSUP) && defined(ENOATTR) - if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES)) { - DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n", - path, strerror(errno) )); - } -#endif - return False; - } - /* Null terminate string. */ - attrstr[sizeret] = 0; - DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr)); - - if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' || - sscanf(attrstr, "%x", &dosattr) != 1) { - DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr)); - return False; - } - - if (S_ISDIR(sbuf->st_mode)) { - dosattr |= aDIR; - } - *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK); - - DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr)); - - if (dosattr & aHIDDEN) DEBUG(8, ("h")); - if (dosattr & aRONLY ) DEBUG(8, ("r")); - if (dosattr & aSYSTEM) DEBUG(8, ("s")); - if (dosattr & aDIR ) DEBUG(8, ("d")); - if (dosattr & aARCH ) DEBUG(8, ("a")); - - DEBUG(8,("\n")); - - return True; -} - -/**************************************************************************** - Set DOS attributes in an EA. -****************************************************************************/ - -static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode) -{ - fstring attrstr; - files_struct *fsp = NULL; - BOOL ret = False; - - snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK); - if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) { - if((errno != EPERM) && (errno != EACCES)) { - return False; - } - - /* We want DOS semantics, ie allow non owner with write permission to change the - bits on a file. Just like file_utime below. - */ - - /* Check if we have write access. */ - if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) - return False; - - /* - * We need to open the file with write access whilst - * still in our current user context. This ensures we - * are not violating security in doing the setxattr. - */ - - fsp = open_file_fchmod(conn,path,sbuf); - if (!fsp) - return ret; - become_root(); - if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) { - ret = True; - } - unbecome_root(); - close_file_fchmod(fsp); - return ret; - } - DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path)); - return True; -} - -/**************************************************************************** - Change a unix mode to a dos mode. -****************************************************************************/ - -uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) -{ - uint32 result = 0; - - DEBUG(8,("dos_mode: %s\n", path)); - - if (!VALID_STAT(*sbuf)) { - return 0; - } - - /* Get the DOS attributes from an EA by preference. */ - if (get_ea_dos_attribute(conn, path, sbuf, &result)) { - return result; - } - - result = dos_mode_from_sbuf(conn, sbuf); - - /* Now do any modifications that depend on the path name. */ - /* hide files with a name starting with a . */ - if (lp_hide_dot_files(SNUM(conn))) { - const char *p = strrchr_m(path,'/'); - if (p) - p++; - else - p = path; - - if (p[0] == '.' && p[1] != '.' && p[1] != 0) - result |= aHIDDEN; - } - - /* Optimization : Only call is_hidden_path if it's not already - hidden. */ - if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { - result |= aHIDDEN; - } - - DEBUG(8,("dos_mode returning ")); - - if (result & aHIDDEN) DEBUG(8, ("h")); - if (result & aRONLY ) DEBUG(8, ("r")); - if (result & aSYSTEM) DEBUG(8, ("s")); - if (result & aDIR ) DEBUG(8, ("d")); - if (result & aARCH ) DEBUG(8, ("a")); - - DEBUG(8,("\n")); - - return(result); -} - -/******************************************************************* - chmod a file - but preserve some bits. -********************************************************************/ - -int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st) -{ - SMB_STRUCT_STAT st1; - int mask=0; - mode_t tmp; - mode_t unixmode; - int ret = -1; - - DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname)); - if (!st) { - st = &st1; - if (SMB_VFS_STAT(conn,fname,st)) - return(-1); - } - - get_acl_group_bits(conn, fname, &st->st_mode); - - if (S_ISDIR(st->st_mode)) - dosmode |= aDIR; - else - dosmode &= ~aDIR; - - if (dos_mode(conn,fname,st) == dosmode) - return(0); - - /* Store the DOS attributes in an EA by preference. */ - if (set_ea_dos_attribute(conn, fname, st, dosmode)) { - return 0; - } - - unixmode = unix_mode(conn,dosmode,fname); - - /* preserve the s bits */ - mask |= (S_ISUID | S_ISGID); - - /* preserve the t bit */ -#ifdef S_ISVTX - mask |= S_ISVTX; -#endif - - /* possibly preserve the x bits */ - if (!MAP_ARCHIVE(conn)) - mask |= S_IXUSR; - if (!MAP_SYSTEM(conn)) - mask |= S_IXGRP; - if (!MAP_HIDDEN(conn)) - mask |= S_IXOTH; - - unixmode |= (st->st_mode & mask); - - /* if we previously had any r bits set then leave them alone */ - if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { - unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH); - unixmode |= tmp; - } - - /* if we previously had any w bits set then leave them alone - whilst adding in the new w bits, if the new mode is not rdonly */ - if (!IS_DOS_READONLY(dosmode)) { - unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); - } - - if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) - return 0; - - if((errno != EPERM) && (errno != EACCES)) - return -1; - - if(!lp_dos_filemode(SNUM(conn))) - return -1; - - /* We want DOS semantics, ie allow non owner with write permission to change the - bits on a file. Just like file_utime below. - */ - - /* Check if we have write access. */ - if (CAN_WRITE(conn)) { - /* - * We need to open the file with write access whilst - * still in our current user context. This ensures we - * are not violating security in doing the fchmod. - * This file open does *not* break any oplocks we are - * holding. We need to review this.... may need to - * break batch oplocks open by others. JRA. - */ - files_struct *fsp = open_file_fchmod(conn,fname,st); - if (!fsp) - return -1; - become_root(); - ret = SMB_VFS_FCHMOD(fsp, fsp->fd, unixmode); - unbecome_root(); - close_file_fchmod(fsp); - } - - return( ret ); -} - -/******************************************************************* - Wrapper around dos_utime that possibly allows DOS semantics rather - than POSIX. -*******************************************************************/ - -int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) -{ - extern struct current_user current_user; - SMB_STRUCT_STAT sb; - int ret = -1; - - errno = 0; - - if(SMB_VFS_UTIME(conn,fname, times) == 0) - return 0; - - if((errno != EPERM) && (errno != EACCES)) - return -1; - - if(!lp_dos_filetimes(SNUM(conn))) - return -1; - - /* We have permission (given by the Samba admin) to - break POSIX semantics and allow a user to change - the time on a file they don't own but can write to - (as DOS does). - */ - - if(SMB_VFS_STAT(conn,fname,&sb) != 0) - return -1; - - /* Check if we have write access. */ - if (CAN_WRITE(conn)) { - if (((sb.st_mode & S_IWOTH) || conn->admin_user || - ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) || - ((sb.st_mode & S_IWGRP) && - in_group(sb.st_gid,current_user.gid, - current_user.ngroups,current_user.groups)))) { - /* We are allowed to become root and change the filetime. */ - become_root(); - ret = SMB_VFS_UTIME(conn,fname, times); - unbecome_root(); - } - } - - return ret; -} - -/******************************************************************* - Change a filetime - possibly allowing DOS semantics. -*******************************************************************/ - -BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime) -{ - struct utimbuf times; - - if (null_mtime(mtime)) - return(True); - - times.modtime = times.actime = mtime; - - if (file_utime(conn, fname, ×)) { - DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); - return False; - } - - return(True); -} diff --git a/source/smbd/error.c b/source/smbd/error.c deleted file mode 100644 index 795bf0949cc..00000000000 --- a/source/smbd/error.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - Unix SMB/CIFS implementation. - error packet handling - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* these can be set by some functions to override the error codes */ -int unix_ERR_class=SMB_SUCCESS; -int unix_ERR_code=0; -NTSTATUS unix_ERR_ntstatus = NT_STATUS_OK; - -/* 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 */ - free((char *)wbmpx); - fsp->wbmpx_ptr = NULL; - 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 eclass=def_class; - int ecode=def_code; - NTSTATUS ntstatus = NT_STATUS_OK; - int i=0; - - if (unix_ERR_class != SMB_SUCCESS) { - eclass = unix_ERR_class; - ecode = unix_ERR_code; - ntstatus = unix_ERR_ntstatus; - unix_ERR_class = SMB_SUCCESS; - unix_ERR_code = 0; - unix_ERR_ntstatus = NT_STATUS_OK; - } else { - 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,ntstatus,eclass,ecode,line,file); -} - - -/**************************************************************************** - Create an error packet. Normally called using the ERROR() macro. -****************************************************************************/ - -int error_packet(char *outbuf,NTSTATUS ntstatus, - uint8 eclass,uint32 ecode,int line, const char *file) -{ - int outsize = set_message(outbuf,0,0,True); - extern uint32 global_client_caps; - - if (errno != 0) - DEBUG(3,("error string = %s\n",strerror(errno))); - -#if defined(DEVELOPER) - if (unix_ERR_class != SMB_SUCCESS || unix_ERR_code != 0 || !NT_STATUS_IS_OK(unix_ERR_ntstatus)) - smb_panic("logic error in error processing"); -#endif - - /* - * We can explicitly force 32 bit error codes even when the - * parameter "nt status" is set to no by pre-setting the - * FLAGS2_32_BIT_ERROR_CODES bit in the smb_flg2 outbuf. - * This is to allow work arounds for client bugs that are needed - * when talking with clients that normally expect nt status codes. JRA. - */ - - if ((lp_nt_status_support() || (SVAL(outbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) && (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)), - nt_errstr(ntstatus))); - return outsize; - } - - if (eclass == 0 && NT_STATUS_V(ntstatus)) - ntstatus_to_dos(ntstatus, &eclass, &ecode); - - 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/fake_file.c b/source/smbd/fake_file.c deleted file mode 100644 index 5ccb548ba5b..00000000000 --- a/source/smbd/fake_file.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - Unix SMB/CIFS implementation. - FAKE FILE suppport, for faking up special files windows want access to - Copyright (C) Stefan (metze) Metzmacher 2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/**************************************************************************** - Open a file with a share mode. -****************************************************************************/ -files_struct *open_fake_file_shared1(enum FAKE_FILE_TYPE fake_file_type, connection_struct *conn,char *fname, - SMB_STRUCT_STAT *psbuf, - uint32 desired_access, - int share_mode,int ofun, uint32 new_dos_attr, int oplock_request, - int *Access,int *action) -{ - extern struct current_user current_user; - int flags=0; - files_struct *fsp = NULL; - - if (fake_file_type == 0) { - return open_file_shared1(conn,fname,psbuf,desired_access, - share_mode,ofun,new_dos_attr, - oplock_request,Access,action); - } - - /* access check */ - if (conn->admin_user != True) { - DEBUG(1,("access_denied to service[%s] file[%s] user[%s]\n", - lp_servicename(SNUM(conn)),fname,conn->user)); - errno = EACCES; - return NULL; - } - - fsp = file_new(conn); - if(!fsp) - return NULL; - - DEBUG(5,("open_fake_file_shared1: fname = %s, FID = %d, share_mode = %x, ofun = %x, oplock request = %d\n", - fname, fsp->fnum, share_mode, ofun, oplock_request )); - - if (!check_name(fname,conn)) { - file_free(fsp); - return NULL; - } - - fsp->fd = -1; - fsp->mode = psbuf->st_mode; - fsp->inode = psbuf->st_ino; - fsp->dev = psbuf->st_dev; - fsp->vuid = current_user.vuid; - fsp->size = psbuf->st_size; - fsp->pos = -1; - fsp->can_lock = True; - fsp->can_read = ((flags & O_WRONLY)==0); - fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); - fsp->share_mode = 0; - fsp->desired_access = desired_access; - fsp->print_file = False; - fsp->modified = False; - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = False; - fsp->is_stat = False; - fsp->directory_delete_on_close = False; - fsp->conn = conn; - string_set(&fsp->fsp_name,fname); - fsp->wcp = NULL; /* Write cache pointer. */ - - fsp->fake_file_handle = init_fake_file_handle(fake_file_type); - - if (fsp->fake_file_handle==NULL) { - file_free(fsp); - return NULL; - } - - conn->num_files_open++; - return fsp; -} - -static FAKE_FILE fake_files[] = { -#ifdef WITH_QUOTAS - {FAKE_FILE_NAME_QUOTA, FAKE_FILE_TYPE_QUOTA, init_quota_handle, destroy_quota_handle}, -#endif /* WITH_QUOTAS */ - {NULL, FAKE_FILE_TYPE_NONE, NULL, NULL } -}; - -int is_fake_file(char *fname) -{ - int i; - - if (!fname) - return 0; - - for (i=0;fake_files[i].name!=NULL;i++) { - if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) { - DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname)); - return fake_files[i].type; - } - } - - return FAKE_FILE_TYPE_NONE; -} - -struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) -{ - TALLOC_CTX *mem_ctx = NULL; - FAKE_FILE_HANDLE *fh = NULL; - int i; - - for (i=0;fake_files[i].name!=NULL;i++) { - if (fake_files[i].type==type) { - DEBUG(5,("init_fake_file_handle: for [%s]\n",fake_files[i].name)); - - if ((mem_ctx=talloc_init("fake_file_handle"))==NULL) { - DEBUG(0,("talloc_init(fake_file_handle) failed.\n")); - return NULL; - } - - if ((fh =(FAKE_FILE_HANDLE *)talloc_zero(mem_ctx, sizeof(FAKE_FILE_HANDLE)))==NULL) { - DEBUG(0,("talloc_zero() failed.\n")); - talloc_destroy(mem_ctx); - return NULL; - } - - fh->type = type; - fh->mem_ctx = mem_ctx; - - if (fake_files[i].init_pd) - fh->pd = fake_files[i].init_pd(fh->mem_ctx); - - fh->free_pd = fake_files[i].free_pd; - - return fh; - } - } - - return NULL; -} - -void destroy_fake_file_handle(FAKE_FILE_HANDLE **fh) -{ - if (!fh||!(*fh)) - return ; - - if ((*fh)->free_pd) - (*fh)->free_pd(&(*fh)->pd); - - talloc_destroy((*fh)->mem_ctx); - (*fh) = NULL; -} diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c deleted file mode 100644 index c2fb6e34566..00000000000 --- a/source/smbd/fileio.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - read/write to a files_struct - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Jeremy Allison 2000-2002. - write cache. - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -static BOOL setup_write_cache(files_struct *, SMB_OFF_T); - -/**************************************************************************** - Read from write cache if we can. -****************************************************************************/ - - -static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) -{ - write_cache *wcp = fsp->wcp; - - if(!wcp) - return False; - - if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) - return False; - - memcpy(data, wcp->data + (pos - wcp->offset), n); - - DO_PROFILE_INC(writecache_read_hits); - - return True; -} - -/**************************************************************************** - 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; - - /* 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)) { - fsp->pos = pos + n; - fsp->position_information = fsp->pos; - return n; - } - - flush_write_cache(fsp, READ_FLUSH); - - fsp->pos = pos; - - if (n > 0) { -#ifdef DMF_FIX - int numretries = 3; -tryagain: - readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos); - - 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 = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos); - - if (readret == -1) - return -1; -#endif - if (readret > 0) - ret += readret; - } - - DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", - fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); - - fsp->pos += ret; - fsp->position_information = fsp->pos; - - return(ret); -} - -/* how many write cache buffers have been allocated */ -static unsigned int allocated_write_caches; - -/**************************************************************************** - *Really* write to a file. -****************************************************************************/ - -static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n) -{ - ssize_t ret; - - if (pos == -1) - ret = vfs_write_data(fsp, data, n); - else { - fsp->pos = pos; - ret = vfs_pwrite_data(fsp, data, n, pos); - } - - DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", - fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); - - if (ret != -1) { - fsp->pos += ret; - -/* Yes - this is correct - writes don't update this. JRA. */ -/* Found by Samba4 tests. */ -#if 0 - fsp->position_information = fsp->pos; -#endif - } - - return ret; -} - -/**************************************************************************** -write to a file -****************************************************************************/ - -ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n) -{ - write_cache *wcp = fsp->wcp; - ssize_t total_written = 0; - int write_path = -1; - - if (fsp->print_file) { - int snum; - uint32 jobid; - - if (!rap_to_pjobid(fsp->rap_print_jobid, &snum, &jobid)) { - DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n", - (unsigned int)fsp->rap_print_jobid )); - errno = EBADF; - return -1; - } - - return print_job_write(SNUM(fsp->conn), jobid, data, n); - } - - if (!fsp->can_write) { - errno = EPERM; - return(0); - } - - if (!fsp->modified) { - SMB_STRUCT_STAT st; - fsp->modified = True; - - if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) { - int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); - fsp->size = (SMB_BIG_UINT)st.st_size; - if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { - file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st); - } - - /* - * If this is the first write and we have an exclusive oplock then setup - * the write cache. - */ - - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { - setup_write_cache(fsp, st.st_size); - wcp = fsp->wcp; - } - } - } - -#ifdef WITH_PROFILE - DO_PROFILE_INC(writecache_total_writes); - if (!fsp->oplock_type) { - DO_PROFILE_INC(writecache_non_oplock_writes); - } -#endif - - /* - * If this file is level II oplocked then we need - * to grab the shared memory lock and inform all - * other files with a level II lock that they need - * to flush their read caches. We keep the lock over - * the shared memory area whilst doing this. - */ - - release_level_2_oplocks_on_change(fsp); - -#ifdef WITH_PROFILE - if (profile_p && profile_p->writecache_total_writes % 500 == 0) { - DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ -nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", - profile_p->writecache_init_writes, - profile_p->writecache_abutted_writes, - profile_p->writecache_total_writes, - profile_p->writecache_non_oplock_writes, - profile_p->writecache_allocated_write_caches, - profile_p->writecache_num_write_caches, - profile_p->writecache_direct_writes, - profile_p->writecache_num_perfect_writes, - profile_p->writecache_read_hits )); - - DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", - profile_p->writecache_flushed_writes[SEEK_FLUSH], - profile_p->writecache_flushed_writes[READ_FLUSH], - profile_p->writecache_flushed_writes[WRITE_FLUSH], - profile_p->writecache_flushed_writes[READRAW_FLUSH], - profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], - profile_p->writecache_flushed_writes[CLOSE_FLUSH], - profile_p->writecache_flushed_writes[SYNC_FLUSH] )); - } -#endif - - if(!wcp) { - DO_PROFILE_INC(writecache_direct_writes); - total_written = real_write_file(fsp, data, pos, n); - if ((total_written != -1) && (pos + total_written > (SMB_OFF_T)fsp->size)) - fsp->size = (SMB_BIG_UINT)(pos + total_written); - return total_written; - } - - DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", - fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); - - fsp->pos = pos + n; - - /* - * If we have active cache and it isn't contiguous then we flush. - * NOTE: There is a small problem with running out of disk .... - */ - - if (wcp->data_size) { - - BOOL cache_flush_needed = False; - - if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) { - - /* ASCII art.... JRA. - - +--------------+----- - | Cached data | Rest of allocated cache buffer.... - +--------------+----- - - +-------------------+ - | Data to write | - +-------------------+ - - */ - - /* - * Start of write overlaps or abutts the existing data. - */ - - size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n); - - memcpy(wcp->data + (pos - wcp->offset), data, data_used); - - /* - * Update the current buffer size with the new data. - */ - - if(pos + data_used > wcp->offset + wcp->data_size) - wcp->data_size = pos + data_used - wcp->offset; - - /* - * Update the file size if changed. - */ - - if (wcp->offset + wcp->data_size > wcp->file_size) { - wcp->file_size = wcp->offset + wcp->data_size; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - /* - * If we used all the data then - * return here. - */ - - if(n == data_used) - return n; - else - cache_flush_needed = True; - - /* - * Move the start of data forward by the amount used, - * cut down the amount left by the same amount. - */ - - data += data_used; - pos += data_used; - n -= data_used; - - DO_PROFILE_INC(writecache_abutted_writes); - total_written = data_used; - - write_path = 1; - - } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && - (pos + n <= wcp->offset + wcp->alloc_size)) { - - /* ASCII art.... JRA. - - +---------------+ - | Cache buffer | - +---------------+ - - +-------------------+ - | Data to write | - +-------------------+ - - */ - - /* - * End of write overlaps the existing data. - */ - - size_t data_used = pos + n - wcp->offset; - - memcpy(wcp->data, data + n - data_used, data_used); - - /* - * Update the current buffer size with the new data. - */ - - if(pos + n > wcp->offset + wcp->data_size) - wcp->data_size = pos + n - wcp->offset; - - /* - * Update the file size if changed. - */ - - if (wcp->offset + wcp->data_size > wcp->file_size) { - wcp->file_size = wcp->offset + wcp->data_size; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - /* - * We don't need to move the start of data, but we - * cut down the amount left by the amount used. - */ - - n -= data_used; - - /* - * We cannot have used all the data here. - */ - - cache_flush_needed = True; - - DO_PROFILE_INC(writecache_abutted_writes); - total_written = data_used; - - 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) ) { - - /* ASCII art.... JRA. - - End of file ---->| - - +---------------+---------------+ - | Cached data | Cache buffer | - +---------------+---------------+ - - +-------------------+ - | Data to write | - +-------------------+ - - */ - - /* - * Non-contiguous write part of which fits within - * 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; - - if(pos + n <= wcp->offset + wcp->alloc_size) - data_used = n; - else - data_used = wcp->offset + wcp->alloc_size - pos; - - /* - * Fill in the non-continuous area with zeros. - */ - - memset(wcp->data + wcp->data_size, '\0', - pos - (wcp->offset + wcp->data_size) ); - - memcpy(wcp->data + (pos - wcp->offset), data, data_used); - - /* - * Update the current buffer size with the new data. - */ - - if(pos + data_used > wcp->offset + wcp->data_size) - wcp->data_size = pos + data_used - wcp->offset; - - /* - * Update the file size if changed. - */ - - if (wcp->offset + wcp->data_size > wcp->file_size) { - wcp->file_size = wcp->offset + wcp->data_size; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - /* - * If we used all the data then - * return here. - */ - - if(n == data_used) - return n; - else - cache_flush_needed = True; - - /* - * Move the start of data forward by the amount used, - * cut down the amount left by the same amount. - */ - - data += data_used; - pos += data_used; - n -= data_used; - - DO_PROFILE_INC(writecache_abutted_writes); - total_written = data_used; - - write_path = 3; - - } else { - - /* ASCII art..... JRA. - - Case 1). - - +---------------+---------------+ - | Cached data | Cache buffer | - +---------------+---------------+ - - +-------------------+ - | Data to write | - +-------------------+ - - Case 2). - - +---------------+---------------+ - | Cached data | Cache buffer | - +---------------+---------------+ - - +-------------------+ - | Data to write | - +-------------------+ - - Case 3). - - +---------------+---------------+ - | Cached data | Cache buffer | - +---------------+---------------+ - - +-----------------------------------------------------+ - | Data to write | - +-----------------------------------------------------+ - - */ - - /* - * Write is bigger than buffer, or there is no overlap on the - * low or high ends. - */ - - DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \ -len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); - - /* - * Update the file size if needed. - */ - - if(pos + n > wcp->file_size) { - wcp->file_size = pos + n; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - /* - * If write would fit in the cache, and is larger than - * the data already in the cache, flush the cache and - * preferentially copy the data new data into it. Otherwise - * just write the data directly. - */ - - if ( n <= wcp->alloc_size && n > wcp->data_size) { - cache_flush_needed = True; - } else { - ssize_t ret = real_write_file(fsp, data, pos, n); - - /* - * If the write overlaps the entire cache, then - * discard the current contents of the cache. - * Fix from Rasmus Borup Hansen rbh@math.ku.dk. - */ - - if ((pos <= wcp->offset) && - (pos + n >= wcp->offset + wcp->data_size) ) { - DEBUG(9,("write_file: discarding overwritten write \ -cache: fd = %d, off=%.0f, size=%u\n", fsp->fd, (double)wcp->offset, (unsigned int)wcp->data_size )); - wcp->data_size = 0; - } - - DO_PROFILE_INC(writecache_direct_writes); - if (ret == -1) - return ret; - - if (pos + ret > wcp->file_size) { - wcp->file_size = pos + ret; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - return ret; - } - - write_path = 4; - - } - - if(wcp->data_size > wcp->file_size) { - wcp->file_size = wcp->data_size; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - if (cache_flush_needed) { - DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ -n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", - write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, - (double)wcp->offset, (unsigned int)wcp->data_size )); - - flush_write_cache(fsp, WRITE_FLUSH); - } - } - - /* - * If the write request is bigger than the cache - * size, write it all out. - */ - - if (n > wcp->alloc_size ) { - ssize_t ret = real_write_file(fsp, data, pos, n); - if (ret == -1) - return -1; - - if (pos + ret > wcp->file_size) { - wcp->file_size = pos + n; - fsp->size = (SMB_BIG_UINT)wcp->file_size; - } - - DO_PROFILE_INC(writecache_direct_writes); - return total_written + n; - } - - /* - * If there's any data left, cache it. - */ - - if (n) { -#ifdef WITH_PROFILE - if (wcp->data_size) { - DO_PROFILE_INC(writecache_abutted_writes); - } else { - DO_PROFILE_INC(writecache_init_writes); - } -#endif - memcpy(wcp->data+wcp->data_size, data, n); - if (wcp->data_size == 0) { - wcp->offset = pos; - DO_PROFILE_INC(writecache_num_write_caches); - } - wcp->data_size += n; - - /* - * Update the file size if changed. - */ - - if (wcp->offset + wcp->data_size > wcp->file_size) { - wcp->file_size = wcp->offset + wcp->data_size; - fsp->size = (SMB_BIG_UINT)wcp->file_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 :) */ - } - - return total_written; -} - -/**************************************************************************** - Delete the write cache structure. -****************************************************************************/ - -void delete_write_cache(files_struct *fsp) -{ - write_cache *wcp; - - if(!fsp) - return; - - if(!(wcp = fsp->wcp)) - return; - - DO_PROFILE_DEC(writecache_allocated_write_caches); - allocated_write_caches--; - - SMB_ASSERT(wcp->data_size == 0); - - SAFE_FREE(wcp->data); - SAFE_FREE(fsp->wcp); - - DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); -} - -/**************************************************************************** - Setup the write cache structure. -****************************************************************************/ - -static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) -{ - ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn)); - write_cache *wcp; - - if (allocated_write_caches >= MAX_WRITE_CACHES) - return False; - - if(alloc_size == 0 || fsp->wcp) - return False; - - if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) { - DEBUG(0,("setup_write_cache: malloc fail.\n")); - return False; - } - - wcp->file_size = file_size; - wcp->offset = 0; - wcp->alloc_size = alloc_size; - wcp->data_size = 0; - 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 )); - 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++; - - DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n", - fsp->fsp_name, (unsigned long)wcp->alloc_size )); - - return True; -} - -/**************************************************************************** - Cope with a size change. -****************************************************************************/ - -void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) -{ - fsp->size = (SMB_BIG_UINT)file_size; - if(fsp->wcp) { - /* 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 = %lu\n", fsp->fsp_name, (unsigned long)fsp->wcp->data_size ); - smb_panic(msg); - } - fsp->wcp->file_size = file_size; - } -} - -/******************************************************************* - Flush a write cache struct to disk. -********************************************************************/ - -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; - - data_size = wcp->data_size; - wcp->data_size = 0; - - DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]); - - DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n", - fsp->fd, (double)wcp->offset, (unsigned int)data_size)); - -#ifdef WITH_PROFILE - if(data_size == wcp->alloc_size) - DO_PROFILE_INC(writecache_num_perfect_writes); -#endif - - 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; -} - -/******************************************************************* -sync a file -********************************************************************/ - -void sync_file(connection_struct *conn, files_struct *fsp) -{ - if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) { - flush_write_cache(fsp, SYNC_FLUSH); - SMB_VFS_FSYNC(fsp,fsp->fd); - } -} - - -/************************************************************ - Perform a stat whether a valid fd or not. -************************************************************/ - -int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) -{ - if (fsp->fd == -1) - return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst); - else - return SMB_VFS_FSTAT(fsp,fsp->fd, pst); -} diff --git a/source/smbd/filename.c b/source/smbd/filename.c deleted file mode 100644 index 805af9c494a..00000000000 --- a/source/smbd/filename.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - Unix SMB/CIFS implementation. - filename handling routines - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Jeremy Allison 1999-2004 - Copyright (C) Ying Chen 2000 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - * New hash table stat cache code added by Ying Chen. - */ - -#include "includes.h" - -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL short_case_preserve; -extern BOOL use_mangled_map; - -static BOOL scan_directory(const char *path, char *name,size_t maxlength, - connection_struct *conn,BOOL docache); - -/**************************************************************************** - Check if two filenames are equal. - This needs to be careful about whether we are case sensitive. -****************************************************************************/ - -static BOOL fname_equal(const char *name1, const char *name2) -{ - /* Normal filename handling */ - if (case_sensitive) - return(strcmp(name1,name2) == 0); - - return(strequal(name1,name2)); -} - -/**************************************************************************** - Mangle the 2nd name and check if it is then equal to the first name. -****************************************************************************/ - -static BOOL mangled_equal(const char *name1, const char *name2, int snum) -{ - pstring tmpname; - - pstrcpy(tmpname, name2); - mangle_map(tmpname, True, False, snum); - return strequal(name1, tmpname); -} - -/**************************************************************************** -This routine is called to convert names from the dos namespace to unix -namespace. It needs to handle any case conversions, mangling, format -changes etc. - -We assume that we have already done a chdir() to the right "root" directory -for this service. - -The function will return False if some part of the name except for the last -part cannot be resolved - -If the saved_last_component != 0, then the unmodified last component -of the pathname is returned there. This is used in an exceptional -case in reply_mv (so far). If saved_last_component == 0 then nothing -is returned there. - -The bad_path arg is set to True if the filename walk failed. This is -used to pick the correct error code to return between ENOENT and ENOTDIR -as Windows applications depend on ERRbadpath being returned if a component -of a pathname does not exist. - -On exit from unix_convert, if *pst was not null, then the file stat -struct will be returned if the file exists and was found, if not this -stat struct will be filled with zeros (and this can be detected by checking -for nlinks = 0, which can never be true for any file). -****************************************************************************/ - -BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_component, - BOOL *bad_path, SMB_STRUCT_STAT *pst) -{ - SMB_STRUCT_STAT st; - char *start, *end; - pstring dirpath; - pstring orig_path; - BOOL component_was_mangled = False; - BOOL name_has_wildcard = False; - - ZERO_STRUCTP(pst); - - *dirpath = 0; - *bad_path = False; - if(saved_last_component) - *saved_last_component = 0; - - if (conn->printer) { - /* we don't ever use the filenames on a printer share as a - filename - so don't convert them */ - return True; - } - - DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); - - /* - * Conversion to basic unix format is already done in check_path_syntax(). - */ - - /* - * Names must be relative to the root of the service - any leading /. - * and trailing /'s should have been trimmed by check_path_syntax(). - */ - -#ifdef DEVELOPER - SMB_ASSERT(*name != '/'); -#endif - - /* - * If we trimmed down to a single '\0' character - * then we should use the "." directory to avoid - * searching the cache, but not if we are in a - * printing share. - * As we know this is valid we can return true here. - */ - - if (!*name) { - name[0] = '.'; - name[1] = '\0'; - return(True); - } - - /* - * Ensure saved_last_component is valid even if file exists. - */ - - if(saved_last_component) { - end = strrchr_m(name, '/'); - if(end) - pstrcpy(saved_last_component, end + 1); - else - pstrcpy(saved_last_component, name); - } - - if (!case_sensitive && (!case_preserve || (mangle_is_8_3(name, False) && !short_case_preserve))) - strnorm(name); - - start = name; - pstrcpy(orig_path, name); - - if(!case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { - *pst = st; - return True; - } - - /* - * stat the name - if it exists then we are all done! - */ - - if (SMB_VFS_STAT(conn,name,&st) == 0) { - stat_cache_add(orig_path, name); - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - *pst = st; - return(True); - } - - DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start)); - - /* - * A special case - if we don't have any mangling chars and are case - * sensitive then searching won't help. - */ - - if (case_sensitive && !mangle_is_mangled(name) && !use_mangled_map) - return(False); - - name_has_wildcard = ms_has_wild(start); - - /* - * is_mangled() was changed to look at an entire pathname, not - * just a component. JRA. - */ - - if (mangle_is_mangled(start)) - component_was_mangled = True; - - /* - * Now we need to recursively match the name against the real - * directory structure. - */ - - /* - * Match each part of the path name separately, trying the names - * as is first, then trying to scan the directory for matching names. - */ - - for (; start ; start = (end?end+1:(char *)NULL)) { - /* - * Pinpoint the end of this section of the filename. - */ - end = strchr_m(start, '/'); - - /* - * Chop the name at this point. - */ - if (end) - *end = 0; - - if(saved_last_component != 0) - pstrcpy(saved_last_component, end ? end + 1 : start); - - /* - * Check if the name exists up to this point. - */ - - if (SMB_VFS_STAT(conn,name, &st) == 0) { - /* - * It exists. it must either be a directory or this must be - * the last part of the path for it to be OK. - */ - if (end && !(st.st_mode & S_IFDIR)) { - /* - * An intermediate part of the name isn't a directory. - */ - DEBUG(5,("Not a dir %s\n",start)); - *end = '/'; - return(False); - } - - if (!end) { - /* - * We just scanned for, and found the end of the path. - * We must return the valid stat struct. - * JRA. - */ - - *pst = st; - } - - } else { - pstring rest; - - /* Stat failed - ensure we don't use it. */ - ZERO_STRUCT(st); - *rest = 0; - - /* - * Remember the rest of the pathname so it can be restored - * later. - */ - - if (end) - pstrcpy(rest,end+1); - - /* - * Try to find this part of the path in the directory. - */ - - if (ms_has_wild(start) || - !scan_directory(dirpath, start, - sizeof(pstring) - 1 - (start - name), - conn, - end?True:False)) { - if (end) { - /* - * An intermediate part of the name can't be found. - */ - DEBUG(5,("Intermediate not found %s\n",start)); - *end = '/'; - - /* - * We need to return the fact that the intermediate - * name resolution failed. This is used to return an - * error of ERRbadpath rather than ERRbadfile. Some - * Windows applications depend on the difference between - * these two errors. - */ - *bad_path = True; - return(False); - } - - /* - * Just the last part of the name doesn't exist. - * 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. - */ - - if (!case_preserve && (!strhasupper(start) || !strhaslower(start))) - strnorm(start); - - /* - * check on the mangled stack to see if we can recover the - * base of the filename. - */ - - if (mangle_is_mangled(start)) { - mangle_check_cache( start ); - } - - DEBUG(5,("New file %s\n",start)); - return(True); - } - - /* - * Restore the rest of the string. If the string was mangled the size - * may have changed. - */ - if (end) { - end = start + strlen(start); - if (!safe_strcat(start, "/", sizeof(pstring) - 1 - (start - name)) || - !safe_strcat(start, rest, sizeof(pstring) - 1 - (start - name))) { - return False; - } - *end = '\0'; - } else { - /* - * We just scanned for, and found the end of the path. - * We must return a valid stat struct if it exists. - * JRA. - */ - - if (SMB_VFS_STAT(conn,name, &st) == 0) { - *pst = st; - } else { - ZERO_STRUCT(st); - } - } - } /* end else */ - - /* - * Add to the dirpath that we have resolved so far. - */ - if (*dirpath) - pstrcat(dirpath,"/"); - - pstrcat(dirpath,start); - - /* - * Don't cache a name with mangled or wildcard components - * as this can change the size. - */ - - if(!component_was_mangled && !name_has_wildcard) - stat_cache_add(orig_path, dirpath); - - /* - * Restore the / that we wiped out earlier. - */ - if (end) - *end = '/'; - } - - /* - * Don't cache a name with mangled or wildcard components - * as this can change the size. - */ - - if(!component_was_mangled && !name_has_wildcard) - stat_cache_add(orig_path, name); - - /* - * The name has been resolved. - */ - - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - return(True); -} - -/**************************************************************************** - Check a filename - possibly caling reducename. - This is called by every routine before it allows an operation on a filename. - It does any final confirmation necessary to ensure that the filename is - a valid one for the user to access. -****************************************************************************/ - -BOOL check_name(pstring name,connection_struct *conn) -{ - BOOL ret = True; - - errno = 0; - - if (IS_VETO_PATH(conn, name)) { - /* Is it not dot or dot dot. */ - if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) { - DEBUG(5,("file path name %s vetoed\n",name)); - return False; - } - } - - if (!lp_widelinks(SNUM(conn))) { - ret = reduce_name(conn,name,conn->connectpath); - } - - /* Check if we are allowing users to follow symlinks */ - /* Patch from David Clerc <David.Clerc@cui.unige.ch> - University of Geneva */ - -#ifdef S_ISLNK - if (!lp_symlinks(SNUM(conn))) { - SMB_STRUCT_STAT statbuf; - if ( (SMB_VFS_LSTAT(conn,name,&statbuf) != -1) && - (S_ISLNK(statbuf.st_mode)) ) { - DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); - ret = False; - } - } -#endif - - if (!ret) - DEBUG(5,("check_name on %s failed\n",name)); - - return(ret); -} - -/**************************************************************************** - Scan a directory to find a filename, matching without case sensitivity. - If the name looks like a mangled name then try via the mangling functions -****************************************************************************/ - -static BOOL scan_directory(const char *path, char *name, size_t maxlength, - connection_struct *conn,BOOL docache) -{ - void *cur_dir; - const char *dname; - BOOL mangled; - - mangled = mangle_is_mangled(name); - - /* handle null paths */ - if (*path == 0) - path = "."; - - if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) { - safe_strcpy(name, dname, maxlength); - return(True); - } - - /* - * The incoming name can be mangled, and if we de-mangle it - * here it will not compare correctly against the filename (name2) - * read from the directory and then mangled by the mangle_map() - * call. We need to mangle both names or neither. - * (JRA). - */ - if (mangled) - mangled = !mangle_check_cache( name ); - - /* open the directory */ - if (!(cur_dir = OpenDir(conn, path, True))) { - DEBUG(3,("scan dir didn't open dir [%s]\n",path)); - return(False); - } - - /* now scan for matching names */ - while ((dname = ReadDirName(cur_dir))) { - - /* Is it dot or dot dot. */ - if ((dname[0] == '.') && (!dname[1] || (dname[1] == '.' && !dname[2]))) { - continue; - } - - /* - * At this point 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,dname,SNUM(conn))) || fname_equal(name, dname)) { - /* we've found the file, change it's name and return */ - if (docache) - DirCacheAdd(path,name,dname,SNUM(conn)); - safe_strcpy(name, dname, maxlength); - CloseDir(cur_dir); - return(True); - } - } - - CloseDir(cur_dir); - return(False); -} diff --git a/source/smbd/files.c b/source/smbd/files.c deleted file mode 100644 index 80544c9a309..00000000000 --- a/source/smbd/files.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Files[] structure handling - Copyright (C) Andrew Tridgell 1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -static int real_max_open_files; - -#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files)) - -#define FILE_HANDLE_OFFSET 0x1000 - -static struct bitmap *file_bmap; - -static files_struct *Files; - -/* a fsp to use when chaining */ -static files_struct *chain_fsp = NULL; -/* a fsp to use to save when breaking an oplock. */ -static files_struct *oplock_save_chain_fsp = NULL; - -static int files_used; - -/**************************************************************************** - 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; - static int first_file; - files_struct *fsp, *next; - - /* we want to give out file handles differently on each new - connection because of a common bug in MS clients where they try to - reuse a file descriptor from an earlier smb connection. This code - increases the chance that the errant client will get an error rather - than causing corruption */ - if (first_file == 0) { - first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files; - } - - i = bitmap_find(file_bmap, first_file); - if (i == -1) { - /* - * Before we give up, go through the open files - * and see if there are any files opened with a - * batch oplock. If so break the oplock and then - * re-use that entry (if it becomes closed). - * This may help as NT/95 clients tend to keep - * files batch oplocked for quite a long time - * after they have finished with them. - */ - for (fsp=Files;fsp;fsp=next) { - next=fsp->next; - if (attempt_close_oplocked_file(fsp)) { - return file_new(conn); - } - } - - DEBUG(0,("ERROR! Out of file structures\n")); - unix_ERR_class = ERRSRV; - unix_ERR_code = ERRnofids; - return NULL; - } - - fsp = (files_struct *)malloc(sizeof(*fsp)); - if (!fsp) { - unix_ERR_class = ERRSRV; - unix_ERR_code = ERRnofids; - return NULL; - } - - 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; - - bitmap_set(file_bmap, i); - files_used++; - - fsp->fnum = i + FILE_HANDLE_OFFSET; - SMB_ASSERT(fsp->fnum < 65536); - - string_set(&fsp->fsp_name,""); - - DLIST_ADD(Files, fsp); - - DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n", - i, fsp->fnum, files_used)); - - chain_fsp = fsp; - - return fsp; -} - -/**************************************************************************** - Close all open files for a connection. -****************************************************************************/ - -void file_close_conn(connection_struct *conn) -{ - files_struct *fsp, *next; - - for (fsp=Files;fsp;fsp=next) { - next = fsp->next; - if (fsp->conn == conn) { - close_file(fsp,False); - } - } -} - -/**************************************************************************** - Close all open files for a pid. -****************************************************************************/ - -void file_close_pid(uint16 smbpid) -{ - files_struct *fsp, *next; - - for (fsp=Files;fsp;fsp=next) { - next = fsp->next; - if (fsp->file_pid == smbpid) { - close_file(fsp,False); - } - } -} - -/**************************************************************************** - Initialise file structures. -****************************************************************************/ - -#define MAX_OPEN_FUDGEFACTOR 20 - -void file_init(void) -{ - int request_max_open_files = lp_max_open_files(); - int real_lim; - - /* - * Set the max_open files to be the requested - * max plus a fudgefactor to allow for the extra - * fd's we need such as log files etc... - */ - real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR); - - real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR; - - if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) - real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES; - - if(real_max_open_files != request_max_open_files) { - DEBUG(1,("file_init: Information only: requested %d \ -open files, %d are available.\n", request_max_open_files, real_max_open_files)); - } - - SMB_ASSERT(real_max_open_files > 100); - - file_bmap = bitmap_allocate(real_max_open_files); - - if (!file_bmap) { - exit_server("out of memory in file_init"); - } - - /* - * Ensure that pipe_handle_oppset is set correctly. - */ - set_pipe_handle_offset(real_max_open_files); -} - -/**************************************************************************** - Close files open by a specified vuid. -****************************************************************************/ - -void file_close_user(int vuid) -{ - files_struct *fsp, *next; - - for (fsp=Files;fsp;fsp=next) { - next=fsp->next; - if (fsp->vuid == vuid) { - close_file(fsp,False); - } - } -} - -void file_dump_open_table(void) -{ - int count=0; - files_struct *fsp; - - for (fsp=Files;fsp;fsp=fsp->next,count++) { - DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n", - count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id, - (unsigned int)fsp->dev, (double)fsp->inode )); - } -} - -/**************************************************************************** - 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 file_id. -****************************************************************************/ - -files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id) -{ - int count=0; - files_struct *fsp; - - for (fsp=Files;fsp;fsp=fsp->next,count++) { - /* We can have a fsp->fd == -1 here as it could be a stat open. */ - if (fsp->dev == dev && - fsp->inode == inode && - fsp->file_id == file_id ) { - if (count > 10) { - DLIST_PROMOTE(Files, fsp); - } - /* Paranoia check. */ - if (fsp->fd == -1 && fsp->oplock_type != NO_OPLOCK) { - DEBUG(0,("file_find_dif: file %s dev = %x, inode = %.0f, file_id = %u \ -oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, (unsigned int)fsp->file_id, - (unsigned int)fsp->oplock_type )); - smb_panic("file_find_dif\n"); - } - return fsp; - } - } - - return NULL; -} - -/**************************************************************************** - Check if an fsp still exists. -****************************************************************************/ - -files_struct *file_find_fsp(files_struct *orig_fsp) -{ - files_struct *fsp; - - for (fsp=Files;fsp;fsp=fsp->next) { - if (fsp == orig_fsp) - return fsp; - } - - return NULL; -} - -/**************************************************************************** - Find the first fsp given a device and inode. -****************************************************************************/ - -files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) -{ - files_struct *fsp; - - for (fsp=Files;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && - fsp->dev == dev && - fsp->inode == inode ) - return fsp; - } - - return NULL; -} - -/**************************************************************************** - Find the next fsp having the same device and inode. -****************************************************************************/ - -files_struct *file_find_di_next(files_struct *start_fsp) -{ - files_struct *fsp; - - for (fsp = start_fsp->next;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && - fsp->dev == start_fsp->dev && - fsp->inode == start_fsp->inode ) - return fsp; - } - - return NULL; -} - -/**************************************************************************** - Find a fsp that is open for printing. -****************************************************************************/ - -files_struct *file_find_print(void) -{ - files_struct *fsp; - - for (fsp=Files;fsp;fsp=fsp->next) { - if (fsp->print_file) return fsp; - } - - return NULL; -} - -/**************************************************************************** - Sync open files on a connection. -****************************************************************************/ - -void file_sync_all(connection_struct *conn) -{ - files_struct *fsp, *next; - - for (fsp=Files;fsp;fsp=next) { - next=fsp->next; - if ((conn == fsp->conn) && (fsp->fd != -1)) { - sync_file(conn,fsp); - } - } -} - -/**************************************************************************** - Free up a fsp. -****************************************************************************/ - -void file_free(files_struct *fsp) -{ - DLIST_REMOVE(Files, fsp); - - string_free(&fsp->fsp_name); - - if (fsp->fake_file_handle) { - destroy_fake_file_handle(&fsp->fake_file_handle); - } - - bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); - files_used--; - - DEBUG(5,("freed files structure %d (%d used)\n", - fsp->fnum, files_used)); - - /* this is paranoia, just in case someone tries to reuse the - information */ - ZERO_STRUCTP(fsp); - - if (fsp == chain_fsp) chain_fsp = NULL; - - SAFE_FREE(fsp); -} - -/**************************************************************************** - 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 (!buf) - return NULL; - fnum = SVAL(buf, where); - - for (fsp=Files;fsp;fsp=fsp->next, count++) { - if (fsp->fnum == fnum) { - chain_fsp = fsp; - if (count > 10) { - DLIST_PROMOTE(Files, fsp); - } - return fsp; - } - } - return NULL; -} - -/**************************************************************************** - Reset the chained fsp - done at the start of a packet reply. -****************************************************************************/ - -void file_chain_reset(void) -{ - chain_fsp = NULL; -} - -/**************************************************************************** -Save the chained fsp - done when about to do an oplock break. -****************************************************************************/ - -void file_chain_save(void) -{ - oplock_save_chain_fsp = chain_fsp; -} - -/**************************************************************************** -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/ipc.c b/source/smbd/ipc.c deleted file mode 100644 index e5465b902c8..00000000000 --- a/source/smbd/ipc.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Inter-process communication and named pipe handling - Copyright (C) Andrew Tridgell 1992-1998 - - SMB Version handling - Copyright (C) John H Terpstra 1995-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - This file handles the named pipe and mailslot calls - in the SMBtrans protocol - */ - -#include "includes.h" - -extern int max_send; - -extern fstring local_machine; - -#define NERR_notsupported 50 - -extern int smb_read_error; - -/******************************************************************* - copies parameters and data, as needed, into the smb buffer - - *both* the data and params sections should be aligned. this - is fudged in the rpc pipes by - at present, only the data section is. this may be a possible - cause of some of the ipc problems being experienced. lkcl26dec97 - - ******************************************************************/ - -static void copy_trans_params_and_data(char *outbuf, int align, - char *rparam, int param_offset, int param_len, - char *rdata, int data_offset, int data_len) -{ - char *copy_into = smb_buf(outbuf)+1; - - if(param_len < 0) - param_len = 0; - - if(data_len < 0) - data_len = 0; - - DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n", - param_offset, param_offset + param_len, - data_offset , data_offset + data_len)); - - if (param_len) - memcpy(copy_into, &rparam[param_offset], param_len); - - copy_into += param_len + align; - - if (data_len ) - memcpy(copy_into, &rdata[data_offset], data_len); -} - -/**************************************************************************** - Send a trans reply. - ****************************************************************************/ - -void send_trans_reply(char *outbuf, - char *rparam, int rparam_len, - char *rdata, int rdata_len, - BOOL buffer_too_large) -{ - int this_ldata,this_lparam; - int tot_data_sent = 0; - int tot_param_sent = 0; - int align; - - int ldata = rdata ? rdata_len : 0; - int lparam = rparam ? rparam_len : 0; - - if (buffer_too_large) - DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata )); - - this_lparam = MIN(lparam,max_send - 500); /* hack */ - this_ldata = MIN(ldata,max_send - (500+this_lparam)); - - align = ((this_lparam)%4); - - if (buffer_too_large) { - ERROR_BOTH(STATUS_BUFFER_OVERFLOW,ERRDOS,ERRmoredata); - } - - set_message(outbuf,10,1+align+this_ldata+this_lparam,True); - - copy_trans_params_and_data(outbuf, align, - rparam, tot_param_sent, this_lparam, - rdata, tot_data_sent, this_ldata); - - SSVAL(outbuf,smb_vwv0,lparam); - SSVAL(outbuf,smb_vwv1,ldata); - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); - SSVAL(outbuf,smb_vwv5,0); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf)); - SSVAL(outbuf,smb_vwv8,0); - SSVAL(outbuf,smb_vwv9,0); - - show_msg(outbuf); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_trans_reply: send_smb failed."); - - tot_data_sent = this_ldata; - tot_param_sent = this_lparam; - - while (tot_data_sent < ldata || tot_param_sent < lparam) - { - this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */ - this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam)); - - if(this_lparam < 0) - this_lparam = 0; - - if(this_ldata < 0) - this_ldata = 0; - - align = (this_lparam%4); - - set_message(outbuf,10,1+this_ldata+this_lparam+align,False); - - copy_trans_params_and_data(outbuf, align, - rparam, tot_param_sent, this_lparam, - rdata, tot_data_sent, this_ldata); - - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); - SSVAL(outbuf,smb_vwv5,tot_param_sent); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf)); - SSVAL(outbuf,smb_vwv8,tot_data_sent); - SSVAL(outbuf,smb_vwv9,0); - - show_msg(outbuf); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_trans_reply: send_smb failed."); - - tot_data_sent += this_ldata; - tot_param_sent += this_lparam; - } -} - -/**************************************************************************** - Start the first part of an RPC reply which began with an SMBtrans request. -****************************************************************************/ - -static BOOL api_rpc_trans_reply(char *outbuf, smb_np_struct *p) -{ - BOOL is_data_outstanding; - char *rdata = malloc(p->max_trans_reply); - int data_len; - - if(rdata == NULL) { - DEBUG(0,("api_rpc_trans_reply: malloc fail.\n")); - return False; - } - - if((data_len = read_from_pipe( p, rdata, p->max_trans_reply, - &is_data_outstanding)) < 0) { - SAFE_FREE(rdata); - return False; - } - - send_trans_reply(outbuf, NULL, 0, rdata, data_len, is_data_outstanding); - - SAFE_FREE(rdata); - return True; -} - -/**************************************************************************** - WaitNamedPipeHandleState -****************************************************************************/ - -static BOOL api_WNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len) -{ - uint16 priority; - - if (!param || param_len < 2) - return False; - - priority = SVAL(param,0); - DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority)); - - if (wait_rpc_pipe_hnd_state(p, priority)) { - /* now send the reply */ - send_trans_reply(outbuf, NULL, 0, NULL, 0, False); - return True; - } - return False; -} - - -/**************************************************************************** - SetNamedPipeHandleState -****************************************************************************/ - -static BOOL api_SNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len) -{ - uint16 id; - - if (!param || param_len < 2) - return False; - - id = SVAL(param,0); - DEBUG(4,("SetNamedPipeHandleState to code %x\n", id)); - - if (set_rpc_pipe_hnd_state(p, id)) { - /* now send the reply */ - send_trans_reply(outbuf, NULL, 0, NULL, 0, False); - return True; - } - return False; -} - - -/**************************************************************************** - When no reply is generated, indicate unsupported. - ****************************************************************************/ - -static BOOL api_no_reply(char *outbuf, int max_rdata_len) -{ - char rparam[4]; - - /* unsupported */ - SSVAL(rparam,0,NERR_notsupported); - SSVAL(rparam,2,0); /* converter word */ - - DEBUG(3,("Unsupported API fd command\n")); - - /* now send the reply */ - send_trans_reply(outbuf, rparam, 4, NULL, 0, False); - - return -1; -} - -/**************************************************************************** - Handle remote api calls delivered to a named pipe already opened. - ****************************************************************************/ - -static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf, - uint16 *setup,char *data,char *params, - int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt) -{ - BOOL reply = False; - smb_np_struct *p = NULL; - int pnum; - int subcommand; - - DEBUG(5,("api_fd_reply\n")); - - /* First find out the name of this file. */ - if (suwcnt != 2) { - DEBUG(0,("Unexpected named pipe transaction.\n")); - return(-1); - } - - /* Get the file handle and hence the file name. */ - /* - * NB. The setup array has already been transformed - * via SVAL and so is in gost byte order. - */ - pnum = ((int)setup[1]) & 0xFFFF; - subcommand = ((int)setup[0]) & 0xFFFF; - - if(!(p = get_rpc_pipe(pnum))) { - if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) { - /* Win9x does this call with a unicode pipe name, not a pnum. */ - /* Just return success for now... */ - DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n")); - send_trans_reply(outbuf, NULL, 0, NULL, 0, False); - return -1; - } - - DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum)); - return api_no_reply(outbuf, mdrcnt); - } - - DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand, p->name, pnum)); - - /* record maximum data length that can be transmitted in an SMBtrans */ - p->max_trans_reply = mdrcnt; - - DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply)); - - switch (subcommand) { - case TRANSACT_DCERPCCMD: - /* dce/rpc command */ - reply = write_to_pipe(p, data, tdscnt); - if (reply) - reply = api_rpc_trans_reply(outbuf, p); - break; - case TRANSACT_WAITNAMEDPIPEHANDLESTATE: - /* Wait Named Pipe Handle state */ - reply = api_WNPHS(outbuf, p, params, tpscnt); - break; - case TRANSACT_SETNAMEDPIPEHANDLESTATE: - /* Set Named Pipe Handle state */ - reply = api_SNPHS(outbuf, p, params, tpscnt); - break; - } - - if (!reply) - return api_no_reply(outbuf, mdrcnt); - - return -1; -} - -/**************************************************************************** - handle named pipe commands - ****************************************************************************/ -static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name, - uint16 *setup,char *data,char *params, - int suwcnt,int tdscnt,int tpscnt, - int msrcnt,int mdrcnt,int mprcnt) -{ - DEBUG(3,("named pipe command on <%s> name\n", name)); - - if (strequal(name,"LANMAN")) - return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt); - - if (strequal(name,"WKSSVC") || - strequal(name,"SRVSVC") || - strequal(name,"WINREG") || - strequal(name,"SAMR") || - strequal(name,"LSARPC")) - { - DEBUG(4,("named pipe command from Win95 (wow!)\n")); - return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt); - } - - if (strlen(name) < 1) - return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt); - - if (setup) - DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1])); - - return 0; -} - - -/**************************************************************************** - Reply to a SMBtrans. - ****************************************************************************/ - -int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize) -{ - fstring name; - int name_offset = 0; - char *data=NULL,*params=NULL; - uint16 *setup=NULL; - int outsize = 0; - uint16 vuid = SVAL(inbuf,smb_uid); - unsigned int tpscnt = SVAL(inbuf,smb_vwv0); - unsigned int tdscnt = SVAL(inbuf,smb_vwv1); - unsigned int mprcnt = SVAL(inbuf,smb_vwv2); - unsigned int mdrcnt = SVAL(inbuf,smb_vwv3); - unsigned int msrcnt = CVAL(inbuf,smb_vwv4); - BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0); - BOOL one_way = BITSETW(inbuf+smb_vwv5,1); - unsigned int pscnt = SVAL(inbuf,smb_vwv9); - unsigned int psoff = SVAL(inbuf,smb_vwv10); - unsigned int dscnt = SVAL(inbuf,smb_vwv11); - unsigned int dsoff = SVAL(inbuf,smb_vwv12); - unsigned int suwcnt = CVAL(inbuf,smb_vwv13); - START_PROFILE(SMBtrans); - - memset(name, '\0',sizeof(name)); - srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE); - - if (dscnt > tdscnt || pscnt > tpscnt) - goto bad_param; - - if (tdscnt) { - if((data = (char *)malloc(tdscnt)) == NULL) { - DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt)); - END_PROFILE(SMBtrans); - return(ERROR_DOS(ERRDOS,ERRnomem)); - } - if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt)) - goto bad_param; - if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) || - (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf))) - goto bad_param; - - memcpy(data,smb_base(inbuf)+dsoff,dscnt); - } - - if (tpscnt) { - if((params = (char *)malloc(tpscnt)) == NULL) { - DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt)); - SAFE_FREE(data); - END_PROFILE(SMBtrans); - return(ERROR_DOS(ERRDOS,ERRnomem)); - } - if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt)) - goto bad_param; - if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) || - (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf))) - goto bad_param; - - memcpy(params,smb_base(inbuf)+psoff,pscnt); - } - - if (suwcnt) { - unsigned int i; - if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) { - DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16)))); - SAFE_FREE(data); - SAFE_FREE(params); - END_PROFILE(SMBtrans); - return(ERROR_DOS(ERRDOS,ERRnomem)); - } - if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size) - goto bad_param; - if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD))) - goto bad_param; - - for (i=0;i<suwcnt;i++) - setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD); - } - - - srv_signing_trans_start(SVAL(inbuf,smb_mid)); - - if (pscnt < tpscnt || dscnt < tdscnt) { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - show_msg(outbuf); - srv_signing_trans_stop(); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_trans: send_smb failed."); - } - - /* receive the rest of the trans packet */ - while (pscnt < tpscnt || dscnt < tdscnt) { - BOOL ret; - unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp; - - ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); - - /* - * The sequence number for the trans reply is always - * based on the last secondary received. - */ - - srv_signing_trans_start(SVAL(inbuf,smb_mid)); - - if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) { - if(ret) { - DEBUG(0,("reply_trans: Invalid secondary trans packet\n")); - } else { - DEBUG(0,("reply_trans: %s in getting secondary trans response.\n", - (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - } - SAFE_FREE(params); - SAFE_FREE(data); - SAFE_FREE(setup); - END_PROFILE(SMBtrans); - srv_signing_trans_stop(); - return(ERROR_DOS(ERRSRV,ERRerror)); - } - - show_msg(inbuf); - - /* Revise total_params and total_data in case they have changed downwards */ - if (SVAL(inbuf,smb_vwv0) < tpscnt) - tpscnt = SVAL(inbuf,smb_vwv0); - if (SVAL(inbuf,smb_vwv1) < tdscnt) - tdscnt = SVAL(inbuf,smb_vwv1); - - pcnt = SVAL(inbuf,smb_vwv2); - poff = SVAL(inbuf,smb_vwv3); - pdisp = SVAL(inbuf,smb_vwv4); - - dcnt = SVAL(inbuf,smb_vwv5); - doff = SVAL(inbuf,smb_vwv6); - ddisp = SVAL(inbuf,smb_vwv7); - - pscnt += pcnt; - dscnt += dcnt; - - if (dscnt > tdscnt || pscnt > tpscnt) - goto bad_param; - - if (pcnt) { - if (pdisp+pcnt >= tpscnt) - goto bad_param; - if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt)) - goto bad_param; - if (pdisp > tpscnt) - goto bad_param; - if ((smb_base(inbuf) + poff + pcnt >= inbuf + bufsize) || - (smb_base(inbuf) + poff + pcnt < smb_base(inbuf))) - goto bad_param; - if (params + pdisp < params) - goto bad_param; - - memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt); - } - - if (dcnt) { - if (ddisp+dcnt >= tdscnt) - goto bad_param; - if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt)) - goto bad_param; - if (ddisp > tdscnt) - goto bad_param; - if ((smb_base(inbuf) + doff + dcnt >= inbuf + bufsize) || - (smb_base(inbuf) + doff + dcnt < smb_base(inbuf))) - goto bad_param; - if (data + ddisp < data) - goto bad_param; - - memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt); - } - } - - DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n", - name,tdscnt,tpscnt,suwcnt)); - - /* - * WinCE wierdness.... - */ - - if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) && - (name[strlen(local_machine)+1] == '\\')) - name_offset = strlen(local_machine)+1; - - if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) { - name_offset += strlen("\\PIPE"); - - /* Win9x weirdness. When talking to a unicode server Win9x - only sends \PIPE instead of \PIPE\ */ - - if (name[name_offset] == '\\') - name_offset++; - - DEBUG(5,("calling named_pipe\n")); - outsize = named_pipe(conn,vuid,outbuf, - name+name_offset,setup,data,params, - suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt); - } else { - DEBUG(3,("invalid pipe name\n")); - outsize = 0; - } - - - SAFE_FREE(data); - SAFE_FREE(params); - SAFE_FREE(setup); - - srv_signing_trans_stop(); - - if (close_on_completion) - close_cnum(conn,vuid); - - if (one_way) { - END_PROFILE(SMBtrans); - return(-1); - } - - if (outsize == 0) { - END_PROFILE(SMBtrans); - return(ERROR_DOS(ERRSRV,ERRnosupport)); - } - - END_PROFILE(SMBtrans); - return(outsize); - - - bad_param: - - srv_signing_trans_stop(); - DEBUG(0,("reply_trans: invalid trans parameters\n")); - SAFE_FREE(data); - SAFE_FREE(params); - SAFE_FREE(setup); - END_PROFILE(SMBtrans); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); -} diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c deleted file mode 100644 index d715ab4ddc3..00000000000 --- a/source/smbd/lanman.c +++ /dev/null @@ -1,3619 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Inter-process communication and named pipe handling - Copyright (C) Andrew Tridgell 1992-1998 - - SMB Version handling - Copyright (C) John H Terpstra 1995-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - This file handles the named pipe and mailslot calls - in the SMBtrans protocol - */ - -#include "includes.h" - -#ifdef CHECK_TYPES -#undef CHECK_TYPES -#endif -#define CHECK_TYPES 0 - -extern fstring local_machine; - -#define NERR_Success 0 -#define NERR_badpass 86 -#define NERR_notsupported 50 - -#define NERR_BASE (2100) -#define NERR_BufTooSmall (NERR_BASE+23) -#define NERR_JobNotFound (NERR_BASE+51) -#define NERR_DestNotFound (NERR_BASE+52) - -#define ACCESS_READ 0x01 -#define ACCESS_WRITE 0x02 -#define ACCESS_CREATE 0x04 - -#define SHPWLEN 8 /* share password length */ - -static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len); -static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len); - - -static int CopyExpanded(connection_struct *conn, - int snum, char** dst, char* src, int* n) -{ - pstring buf; - int l; - - if (!src || !dst || !n || !(*dst)) return(0); - - StrnCpy(buf,src,sizeof(buf)/2); - pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf,sizeof(buf)); - l = push_ascii(*dst,buf,*n, STR_TERMINATE); - (*dst) += l; - (*n) -= l; - return l; -} - -static int CopyAndAdvance(char** dst, char* src, int* n) -{ - int l; - if (!src || !dst || !n || !(*dst)) return(0); - l = push_ascii(*dst,src,*n, STR_TERMINATE); - (*dst) += l; - (*n) -= l; - return l; -} - -static int StrlenExpanded(connection_struct *conn, int snum, char* s) -{ - pstring buf; - if (!s) return(0); - StrnCpy(buf,s,sizeof(buf)/2); - pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf,sizeof(buf)); - return strlen(buf) + 1; -} - -static char* Expand(connection_struct *conn, int snum, char* s) -{ - static pstring buf; - if (!s) return(NULL); - StrnCpy(buf,s,sizeof(buf)/2); - pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf,sizeof(buf)); - return &buf[0]; -} - -/******************************************************************* - check a API string for validity when we only need to check the prefix - ******************************************************************/ -static BOOL prefix_ok(const char *str, const char *prefix) -{ - return(strncmp(str,prefix,strlen(prefix)) == 0); -} - -struct pack_desc { - const char* format; /* formatstring for structure */ - const char* subformat; /* subformat for structure */ - char* base; /* baseaddress of buffer */ - int buflen; /* remaining size for fixed part; on init: length of base */ - int subcount; /* count of substructures */ - char* structbuf; /* pointer into buffer for remaining fixed part */ - int stringlen; /* remaining size for variable part */ - char* stringbuf; /* pointer into buffer for remaining variable part */ - int neededlen; /* total needed size */ - int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */ - const char* curpos; /* current position; pointer into format or subformat */ - int errcode; -}; - -static int get_counter(const char** p) -{ - int i, n; - if (!p || !(*p)) return(1); - if (!isdigit((int)**p)) return 1; - for (n = 0;;) { - i = **p; - if (isdigit(i)) - n = 10 * n + (i - '0'); - else - return n; - (*p)++; - } -} - -static int getlen(const char* p) -{ - int n = 0; - if (!p) return(0); - while (*p) { - switch( *p++ ) { - case 'W': /* word (2 byte) */ - n += 2; - break; - case 'K': /* status word? (2 byte) */ - n += 2; - break; - case 'N': /* count of substructures (word) at end */ - n += 2; - break; - case 'D': /* double word (4 byte) */ - case 'z': /* offset to zero terminated string (4 byte) */ - case 'l': /* offset to user data (4 byte) */ - n += 4; - break; - case 'b': /* offset to data (with counter) (4 byte) */ - n += 4; - get_counter(&p); - break; - case 'B': /* byte (with optional counter) */ - n += get_counter(&p); - break; - } - } - return n; -} - -static BOOL init_package(struct pack_desc* p, int count, int subcount) -{ - int n = p->buflen; - int i; - - if (!p->format || !p->base) return(False); - - i = count * getlen(p->format); - if (p->subformat) i += subcount * getlen(p->subformat); - p->structbuf = p->base; - p->neededlen = 0; - p->usedlen = 0; - p->subcount = 0; - p->curpos = p->format; - if (i > n) { - p->neededlen = i; - i = n = 0; -#if 0 - /* - * This is the old error code we used. Aparently - * WinNT/2k systems return ERRbuftoosmall (2123) and - * OS/2 needs this. I'm leaving this here so we can revert - * if needed. JRA. - */ - p->errcode = ERRmoredata; -#else - p->errcode = ERRbuftoosmall; -#endif - } - else - p->errcode = NERR_Success; - p->buflen = i; - n -= i; - p->stringbuf = p->base + i; - p->stringlen = n; - return(p->errcode == NERR_Success); -} - -static int package(struct pack_desc* p, ...) -{ - va_list args; - int needed=0, stringneeded; - const char* str=NULL; - int is_string=0, stringused; - int32 temp; - - va_start(args,p); - - if (!*p->curpos) { - if (!p->subcount) - p->curpos = p->format; - else { - p->curpos = p->subformat; - p->subcount--; - } - } -#if CHECK_TYPES - str = va_arg(args,char*); - SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0); -#endif - stringneeded = -1; - - if (!p->curpos) { - va_end(args); - return(0); - } - - switch( *p->curpos++ ) { - case 'W': /* word (2 byte) */ - needed = 2; - temp = va_arg(args,int); - if (p->buflen >= needed) SSVAL(p->structbuf,0,temp); - break; - case 'K': /* status word? (2 byte) */ - needed = 2; - temp = va_arg(args,int); - if (p->buflen >= needed) SSVAL(p->structbuf,0,temp); - break; - case 'N': /* count of substructures (word) at end */ - needed = 2; - p->subcount = va_arg(args,int); - if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount); - break; - case 'D': /* double word (4 byte) */ - needed = 4; - temp = va_arg(args,int); - if (p->buflen >= needed) SIVAL(p->structbuf,0,temp); - break; - case 'B': /* byte (with optional counter) */ - needed = get_counter(&p->curpos); - { - char *s = va_arg(args,char*); - if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1); - } - break; - case 'z': /* offset to zero terminated string (4 byte) */ - str = va_arg(args,char*); - stringneeded = (str ? strlen(str)+1 : 0); - is_string = 1; - break; - case 'l': /* offset to user data (4 byte) */ - str = va_arg(args,char*); - stringneeded = va_arg(args,int); - is_string = 0; - break; - case 'b': /* offset to data (with counter) (4 byte) */ - str = va_arg(args,char*); - stringneeded = get_counter(&p->curpos); - is_string = 0; - break; - } - va_end(args); - if (stringneeded >= 0) { - needed = 4; - if (p->buflen >= needed) { - stringused = stringneeded; - if (stringused > p->stringlen) { - stringused = (is_string ? p->stringlen : 0); - if (p->errcode == NERR_Success) p->errcode = ERRmoredata; - } - if (!stringused) - SIVAL(p->structbuf,0,0); - else { - SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base)); - memcpy(p->stringbuf,str?str:"",stringused); - if (is_string) p->stringbuf[stringused-1] = '\0'; - p->stringbuf += stringused; - p->stringlen -= stringused; - p->usedlen += stringused; - } - } - p->neededlen += stringneeded; - } - p->neededlen += needed; - if (p->buflen >= needed) { - p->structbuf += needed; - p->buflen -= needed; - p->usedlen += needed; - } - else { - if (p->errcode == NERR_Success) p->errcode = ERRmoredata; - } - return 1; -} - -#if CHECK_TYPES -#define PACK(desc,t,v) package(desc,t,v,0,0,0,0) -#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0) -#else -#define PACK(desc,t,v) package(desc,v) -#define PACKl(desc,t,v,l) package(desc,v,l) -#endif - -static void PACKI(struct pack_desc* desc, const char *t,int v) -{ - PACK(desc,t,v); -} - -static void PACKS(struct pack_desc* desc,const char *t,const char *v) -{ - PACK(desc,t,v); -} - - -/**************************************************************************** - get a print queue - ****************************************************************************/ -static void PackDriverData(struct pack_desc* desc) -{ - char drivdata[4+4+32]; - SIVAL(drivdata,0,sizeof drivdata); /* cb */ - SIVAL(drivdata,4,1000); /* lVersion */ - memset(drivdata+8,0,32); /* szDeviceName */ - push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE); - PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */ -} - -static int check_printq_info(struct pack_desc* desc, - int uLevel, char *id1, char *id2) -{ - desc->subformat = NULL; - switch( uLevel ) { - case 0: - desc->format = "B13"; - break; - case 1: - desc->format = "B13BWWWzzzzzWW"; - break; - case 2: - desc->format = "B13BWWWzzzzzWN"; - desc->subformat = "WB21BB16B10zWWzDDz"; - break; - case 3: - desc->format = "zWWWWzzzzWWzzl"; - break; - case 4: - desc->format = "zWWWWzzzzWNzzl"; - desc->subformat = "WWzWWDDzz"; - break; - case 5: - desc->format = "z"; - break; - case 51: - desc->format = "K"; - break; - case 52: - desc->format = "WzzzzzzzzN"; - desc->subformat = "z"; - break; - default: return False; - } - if (strcmp(desc->format,id1) != 0) return False; - if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False; - return True; -} - - -#define RAP_JOB_STATUS_QUEUED 0 -#define RAP_JOB_STATUS_PAUSED 1 -#define RAP_JOB_STATUS_SPOOLING 2 -#define RAP_JOB_STATUS_PRINTING 3 -#define RAP_JOB_STATUS_PRINTED 4 - -#define RAP_QUEUE_STATUS_PAUSED 1 -#define RAP_QUEUE_STATUS_ERROR 2 - -/* turn a print job status into a on the wire status -*/ -static int printj_status(int v) -{ - switch (v) { - case LPQ_QUEUED: - return RAP_JOB_STATUS_QUEUED; - case LPQ_PAUSED: - return RAP_JOB_STATUS_PAUSED; - case LPQ_SPOOLING: - return RAP_JOB_STATUS_SPOOLING; - case LPQ_PRINTING: - return RAP_JOB_STATUS_PRINTING; - } - return 0; -} - -/* turn a print queue status into a on the wire status -*/ -static int printq_status(int v) -{ - switch (v) { - case LPQ_QUEUED: - return 0; - case LPQ_PAUSED: - return RAP_QUEUE_STATUS_PAUSED; - } - return RAP_QUEUE_STATUS_ERROR; -} - -static void fill_printjob_info(connection_struct *conn, int snum, int uLevel, - struct pack_desc* desc, - print_queue_struct* queue, int n) -{ - time_t t = queue->time; - - /* the client expects localtime */ - t -= TimeDiff(t); - - PACKI(desc,"W",pjobid_to_rap(snum,queue->job)); /* uJobId */ - if (uLevel == 1) { - PACKS(desc,"B21",queue->fs_user); /* szUserName */ - PACKS(desc,"B",""); /* pad */ - PACKS(desc,"B16",""); /* szNotifyName */ - PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */ - PACKS(desc,"z",""); /* pszParms */ - PACKI(desc,"W",n+1); /* uPosition */ - PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKI(desc,"D",t); /* ulSubmitted */ - PACKI(desc,"D",queue->size); /* ulSize */ - PACKS(desc,"z",queue->fs_file); /* pszComment */ - } - if (uLevel == 2 || uLevel == 3 || uLevel == 4) { - PACKI(desc,"W",queue->priority); /* uPriority */ - PACKS(desc,"z",queue->fs_user); /* pszUserName */ - PACKI(desc,"W",n+1); /* uPosition */ - PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */ - PACKI(desc,"D",t); /* ulSubmitted */ - PACKI(desc,"D",queue->size); /* ulSize */ - PACKS(desc,"z","Samba"); /* pszComment */ - PACKS(desc,"z",queue->fs_file); /* pszDocument */ - if (uLevel == 3) { - PACKS(desc,"z",""); /* pszNotifyName */ - PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */ - PACKS(desc,"z",""); /* pszParms */ - PACKS(desc,"z",""); /* pszStatus */ - PACKS(desc,"z",SERVICE(snum)); /* pszQueue */ - PACKS(desc,"z","lpd"); /* pszQProcName */ - PACKS(desc,"z",""); /* pszQProcParms */ - PACKS(desc,"z","NULL"); /* pszDriverName */ - PackDriverData(desc); /* pDriverData */ - PACKS(desc,"z",""); /* pszPrinterName */ - } else if (uLevel == 4) { /* OS2 */ - PACKS(desc,"z",""); /* pszSpoolFileName */ - PACKS(desc,"z",""); /* pszPortName */ - PACKS(desc,"z",""); /* pszStatus */ - PACKI(desc,"D",0); /* ulPagesSpooled */ - PACKI(desc,"D",0); /* ulPagesSent */ - PACKI(desc,"D",0); /* ulPagesPrinted */ - PACKI(desc,"D",0); /* ulTimePrinted */ - PACKI(desc,"D",0); /* ulExtendJobStatus */ - PACKI(desc,"D",0); /* ulStartPage */ - PACKI(desc,"D",0); /* ulEndPage */ - } - } -} - -/******************************************************************** - Return a driver name given an snum. - Returns True if from tdb, False otherwise. - ********************************************************************/ - -static BOOL get_driver_name(int snum, pstring drivername) -{ - NT_PRINTER_INFO_LEVEL *info = NULL; - BOOL in_tdb = False; - - get_a_printer (NULL, &info, 2, lp_servicename(snum)); - if (info != NULL) { - pstrcpy( drivername, info->info_2->drivername); - in_tdb = True; - free_a_printer(&info, 2); - } - - return in_tdb; -} - -/******************************************************************** - Respond to the DosPrintQInfo command with a level of 52 - This is used to get printer driver information for Win9x clients - ********************************************************************/ -static void fill_printq_info_52(connection_struct *conn, int snum, - struct pack_desc* desc, int count ) -{ - int i; - fstring location; - NT_PRINTER_DRIVER_INFO_LEVEL driver; - NT_PRINTER_INFO_LEVEL *printer = NULL; - - ZERO_STRUCT(driver); - - if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) { - DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", - lp_servicename(snum))); - goto err; - } - - if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, - "Windows 4.0", 0)) ) - { - DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", - printer->info_2->drivername)); - goto err; - } - - trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0); - trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0); - trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0); - - PACKI(desc, "W", 0x0400); /* don't know */ - PACKS(desc, "z", driver.info_3->name); /* long printer name */ - PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */ - PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */ - PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */ - - fstrcpy(location, "\\\\"); - fstrcat(location, get_called_name()); - fstrcat(location, "\\print$\\WIN40\\0"); - PACKS(desc,"z", location); /* share to retrieve files */ - - PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */ - PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */ - PACKS(desc,"z", driver.info_3->driverpath); /* driver name */ - - DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name)); - DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath)); - DEBUG(3,("Data File: %s:\n",driver.info_3->datafile)); - DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname)); - DEBUG(3,("Driver Location: %s:\n",location)); - DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype)); - DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile)); - PACKI(desc,"N",count); /* number of files to copy */ - - for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++) - { - trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0); - PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */ - DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i])); - } - - /* sanity check */ - if ( i != count ) - DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n", - count, i)); - - DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i)); - - desc->errcode=NERR_Success; - goto done; - -err: - DEBUG(3,("fill_printq_info: Can't supply driver files\n")); - desc->errcode=NERR_notsupported; - -done: - if ( printer ) - free_a_printer( &printer, 2 ); - - if ( driver.info_3 ) - free_a_printer_driver( driver, 3 ); -} - - -static void fill_printq_info(connection_struct *conn, int snum, int uLevel, - struct pack_desc* desc, - int count, print_queue_struct* queue, - print_status_struct* status) -{ - switch (uLevel) { - case 1: - case 2: - PACKS(desc,"B13",SERVICE(snum)); - break; - case 3: - case 4: - case 5: - PACKS(desc,"z",Expand(conn,snum,SERVICE(snum))); - break; - case 51: - PACKI(desc,"K",printq_status(status->status)); - break; - } - - if (uLevel == 1 || uLevel == 2) { - PACKS(desc,"B",""); /* alignment */ - PACKI(desc,"W",5); /* priority */ - PACKI(desc,"W",0); /* start time */ - PACKI(desc,"W",0); /* until time */ - PACKS(desc,"z",""); /* pSepFile */ - PACKS(desc,"z","lpd"); /* pPrProc */ - PACKS(desc,"z",SERVICE(snum)); /* pDestinations */ - PACKS(desc,"z",""); /* pParms */ - if (snum < 0) { - PACKS(desc,"z","UNKNOWN PRINTER"); - PACKI(desc,"W",LPSTAT_ERROR); - } - else if (!status || !status->message[0]) { - PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); - PACKI(desc,"W",LPSTAT_OK); /* status */ - } else { - PACKS(desc,"z",status->message); - PACKI(desc,"W",printq_status(status->status)); /* status */ - } - PACKI(desc,(uLevel == 1 ? "W" : "N"),count); - } - - if (uLevel == 3 || uLevel == 4) { - pstring drivername; - - PACKI(desc,"W",5); /* uPriority */ - PACKI(desc,"W",0); /* uStarttime */ - PACKI(desc,"W",0); /* uUntiltime */ - PACKI(desc,"W",5); /* pad1 */ - PACKS(desc,"z",""); /* pszSepFile */ - 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 { - PACKI(desc,"W",printq_status(status->status)); /* fsStatus */ - } - PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */ - PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */ - get_driver_name(snum,drivername); - PACKS(desc,"z",drivername); /* pszDriverName */ - PackDriverData(desc); /* pDriverData */ - } - - if (uLevel == 2 || uLevel == 4) { - int i; - for (i=0;i<count;i++) - fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i); - } - - if (uLevel==52) - fill_printq_info_52( conn, snum, desc, count ); -} - -/* This function returns the number of files for a given driver */ -static int get_printerdrivernumber(int snum) -{ - int result = 0; - NT_PRINTER_DRIVER_INFO_LEVEL driver; - NT_PRINTER_INFO_LEVEL *printer = NULL; - - ZERO_STRUCT(driver); - - if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) { - DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n", - lp_servicename(snum))); - goto done; - } - - if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, - "Windows 4.0", 0)) ) - { - DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", - printer->info_2->drivername)); - goto done; - } - - /* count the number of files */ - while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] ) - result++; - \ - done: - if ( printer ) - free_a_printer( &printer, 2 ); - - if ( driver.info_3 ) - free_a_printer_driver( driver, 3 ); - - return result; -} - -static BOOL api_DosPrintQGetInfo(connection_struct *conn, - uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char *QueueName = p; - int uLevel; - int count=0; - int snum; - char* str3; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - char* tmpdata=NULL; - - memset((char *)&status,'\0',sizeof(status)); - memset((char *)&desc,'\0',sizeof(desc)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - str3 = p + 4; - - /* remove any trailing username */ - if ((p = strchr_m(QueueName,'%'))) - *p = 0; - - DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName)); - - /* check it's a supported varient */ - if (!prefix_ok(str1,"zWrLh")) - return False; - if (!check_printq_info(&desc,uLevel,str2,str3)) { - /* - * Patch from Scott Moomaw <scott@bridgewater.edu> - * to return the 'invalid info level' error if an - * unknown level was requested. - */ - *rdata_len = 0; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,ERRunknownlevel); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,0); - return(True); - } - - snum = lp_servicenumber(QueueName); - if (snum < 0 && pcap_printername_ok(QueueName,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(QueueName,pnum); - snum = lp_servicenumber(QueueName); - } - } - - if (snum < 0 || !VALID_SNUM(snum)) - return(False); - - if (uLevel==52) { - count = get_printerdrivernumber(snum); - DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count)); - } else { - count = print_queue_status(snum, &queue,&status); - } - - if (mdrcnt > 0) { - *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - } else { - /* - * Don't return data but need to get correct length - * init_package will return wrong size if buflen=0 - */ - desc.buflen = getlen(desc.format); - desc.base = tmpdata = (char *) malloc (desc.buflen); - } - - if (init_package(&desc,1,count)) { - desc.subcount = count; - fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status); - } - - *rdata_len = desc.usedlen; - - /* - * We must set the return code to ERRbuftoosmall - * in order to support lanman style printing with Win NT/2k - * clients --jerry - */ - if (!mdrcnt && lp_disable_spoolss()) - desc.errcode = ERRbuftoosmall; - - *rdata_len = desc.usedlen; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode)); - - SAFE_FREE(queue); - SAFE_FREE(tmpdata); - - return(True); -} - -/**************************************************************************** - View list of all print jobs on all queues. -****************************************************************************/ - -static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data, - int mdrcnt, int mprcnt, - char **rdata, char** rparam, - int *rdata_len, int *rparam_len) -{ - char *param_format = param+2; - char *output_format1 = skip_string(param_format,1); - char *p = skip_string(output_format1,1); - int uLevel = SVAL(p,0); - char *output_format2 = p + 4; - int services = lp_numservices(); - int i, n; - struct pack_desc desc; - print_queue_struct **queue = NULL; - print_status_struct *status = NULL; - int* subcntarr = NULL; - int queuecnt, subcnt=0, succnt=0; - - memset((char *)&desc,'\0',sizeof(desc)); - - DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel)); - - if (!prefix_ok(param_format,"WrLeh")) return False; - if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) { - /* - * Patch from Scott Moomaw <scott@bridgewater.edu> - * to return the 'invalid info level' error if an - * unknown level was requested. - */ - *rdata_len = 0; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,ERRunknownlevel); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,0); - return(True); - } - - queuecnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) - queuecnt++; - if (uLevel > 0) { - if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) { - DEBUG(0,("api_DosPrintQEnum: malloc fail !\n")); - return False; - } - memset(queue,0,queuecnt*sizeof(print_queue_struct*)); - if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) { - DEBUG(0,("api_DosPrintQEnum: malloc fail !\n")); - return False; - } - memset(status,0,queuecnt*sizeof(print_status_struct)); - if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) { - DEBUG(0,("api_DosPrintQEnum: malloc fail !\n")); - return False; - } - subcnt = 0; - n = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - subcntarr[n] = print_queue_status(i, &queue[n],&status[n]); - subcnt += subcntarr[n]; - n++; - } - } - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - - if (init_package(&desc,queuecnt,subcnt)) { - n = 0; - succnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]); - n++; - if (desc.errcode == NERR_Success) succnt = n; - } - } - - SAFE_FREE(subcntarr); - - *rdata_len = desc.usedlen; - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,queuecnt); - - for (i = 0; i < queuecnt; i++) { - if (queue) SAFE_FREE(queue[i]); - } - - SAFE_FREE(queue); - SAFE_FREE(status); - - return True; -} - -/**************************************************************************** - get info level for a server list query - ****************************************************************************/ -static BOOL check_server_info(int uLevel, char* id) -{ - switch( uLevel ) { - case 0: - if (strcmp(id,"B16") != 0) return False; - break; - case 1: - if (strcmp(id,"B16BBDz") != 0) return False; - break; - default: - return False; - } - return True; -} - -struct srv_info_struct -{ - fstring name; - uint32 type; - fstring comment; - fstring domain; - BOOL server_added; -}; - - -/******************************************************************* - get server info lists from the files saved by nmbd. Return the - number of entries - ******************************************************************/ -static int get_server_info(uint32 servertype, - struct srv_info_struct **servers, - const char *domain) -{ - int count=0; - int alloced=0; - char **lines; - BOOL local_list_only; - int i; - - lines = file_lines_load(lock_path(SERVER_LIST), NULL); - if (!lines) { - DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno))); - return(0); - } - - /* request for everything is code for request all servers */ - if (servertype == SV_TYPE_ALL) - servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); - - local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY); - - DEBUG(4,("Servertype search: %8x\n",servertype)); - - for (i=0;lines[i];i++) { - fstring stype; - struct srv_info_struct *s; - const char *ptr = lines[i]; - BOOL ok = True; - - if (!*ptr) continue; - - if (count == alloced) { - struct srv_info_struct *ts; - - alloced += 10; - 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; - memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count)); - } - s = &(*servers)[count]; - - if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue; - if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue; - if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue; - if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) { - /* this allows us to cope with an old nmbd */ - fstrcpy(s->domain,lp_workgroup()); - } - - if (sscanf(stype,"%X",&s->type) != 1) { - DEBUG(4,("r:host file ")); - ok = False; - } - - /* Filter the servers/domains we return based on what was asked for. */ - - /* Check to see if we are being asked for a local list only. */ - if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) { - DEBUG(4,("r: local list only")); - ok = False; - } - - /* doesn't match up: don't want it */ - if (!(servertype & s->type)) { - DEBUG(4,("r:serv type ")); - ok = False; - } - - if ((servertype & SV_TYPE_DOMAIN_ENUM) != - (s->type & SV_TYPE_DOMAIN_ENUM)) - { - DEBUG(4,("s: dom mismatch ")); - ok = False; - } - - if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) - { - ok = False; - } - - /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */ - s->type &= ~SV_TYPE_LOCAL_LIST_ONLY; - - if (ok) - { - DEBUG(4,("**SV** %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - - s->server_added = True; - count++; - } - else - { - DEBUG(4,("%20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - } - } - - file_lines_free(lines); - return(count); -} - - -/******************************************************************* - fill in a server info structure - ******************************************************************/ -static int fill_srv_info(struct srv_info_struct *service, - int uLevel, char **buf, int *buflen, - char **stringbuf, int *stringspace, char *baseaddr) -{ - int struct_len; - char* p; - char* p2; - int l2; - int len; - - switch (uLevel) { - case 0: struct_len = 16; break; - case 1: struct_len = 26; break; - default: return -1; - } - - if (!buf) - { - len = 0; - switch (uLevel) - { - case 1: - len = strlen(service->comment)+1; - break; - } - - if (buflen) *buflen = struct_len; - if (stringspace) *stringspace = len; - return struct_len + len; - } - - len = struct_len; - p = *buf; - if (*buflen < struct_len) return -1; - if (stringbuf) - { - p2 = *stringbuf; - l2 = *stringspace; - } - else - { - p2 = p + struct_len; - l2 = *buflen - struct_len; - } - if (!baseaddr) baseaddr = p; - - switch (uLevel) - { - case 0: - push_ascii(p,service->name, 15, STR_TERMINATE); - break; - - case 1: - push_ascii(p,service->name,15, STR_TERMINATE); - SIVAL(p,18,service->type); - SIVAL(p,22,PTR_DIFF(p2,baseaddr)); - len += CopyAndAdvance(&p2,service->comment,&l2); - break; - } - - if (stringbuf) - { - *buf = p + struct_len; - *buflen -= struct_len; - *stringbuf = p2; - *stringspace = l2; - } - else - { - *buf = p2; - *buflen -= len; - } - return len; -} - - -static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2) -{ - return(strcmp(s1->name,s2->name)); -} - -/**************************************************************************** - view list of servers available (or possibly domains). The info is - extracted from lists saved by nmbd on the local host - ****************************************************************************/ -static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data, - int mdrcnt, int mprcnt, char **rdata, - char **rparam, int *rdata_len, int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - uint32 servertype = IVAL(p,4); - char *p2; - int data_len, fixed_len, string_len; - int f_len = 0, s_len = 0; - struct srv_info_struct *servers=NULL; - int counted=0,total=0; - int i,missed; - fstring domain; - BOOL domain_request; - BOOL local_request; - - /* If someone sets all the bits they don't really mean to set - DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the - known servers. */ - - if (servertype == SV_TYPE_ALL) - servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); - - /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set - any other bit (they may just set this bit on it's own) they - want all the locally seen servers. However this bit can be - set on its own so set the requested servers to be - ALL - DOMAIN_ENUM. */ - - if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) - servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); - - domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0); - local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0); - - p += 8; - - if (!prefix_ok(str1,"WrLehD")) return False; - if (!check_server_info(uLevel,str2)) return False; - - DEBUG(4, ("server request level: %s %8x ", str2, servertype)); - DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); - DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); - - if (strcmp(str1, "WrLehDz") == 0) { - pull_ascii_fstring(domain, p); - } else { - fstrcpy(domain, lp_workgroup()); - } - - if (lp_browse_list()) - total = get_server_info(servertype,&servers,domain); - - data_len = fixed_len = string_len = 0; - missed = 0; - - if (total > 0) - qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); - - { - char *lastname=NULL; - - for (i=0;i<total;i++) - { - struct srv_info_struct *s = &servers[i]; - if (lastname && strequal(lastname,s->name)) continue; - lastname = s->name; - data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0); - DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - - if (data_len <= buf_len) { - counted++; - fixed_len += f_len; - string_len += s_len; - } else { - missed++; - } - } - } - - *rdata_len = fixed_len + string_len; - *rdata = REALLOC(*rdata,*rdata_len); - memset(*rdata,'\0',*rdata_len); - - p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */ - p = *rdata; - f_len = fixed_len; - s_len = string_len; - - { - char *lastname=NULL; - int count2 = counted; - for (i = 0; i < total && count2;i++) - { - struct srv_info_struct *s = &servers[i]; - if (lastname && strequal(lastname,s->name)) continue; - lastname = s->name; - fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); - DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - count2--; - } - } - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata)); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,counted+missed); - - SAFE_FREE(servers); - - DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", - domain,uLevel,counted,counted+missed)); - - return(True); -} - -/**************************************************************************** - command 0x34 - suspected of being a "Lookup Names" stub api - ****************************************************************************/ -static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data, - int mdrcnt, int mprcnt, char **rdata, - char **rparam, int *rdata_len, int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - int counted=0; - int missed=0; - - DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n", - str1, str2, p, uLevel, buf_len)); - - if (!prefix_ok(str1,"zWrLeh")) return False; - - *rdata_len = 0; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - SSVAL(*rparam,0,0x08AC); /* informational warning message */ - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,counted+missed); - - return(True); -} - -/**************************************************************************** - get info about a share - ****************************************************************************/ -static BOOL check_share_info(int uLevel, char* id) -{ - switch( uLevel ) { - case 0: - if (strcmp(id,"B13") != 0) return False; - break; - case 1: - if (strcmp(id,"B13BWz") != 0) return False; - break; - case 2: - if (strcmp(id,"B13BWzWWWzB9B") != 0) return False; - break; - case 91: - if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False; - break; - default: return False; - } - return True; -} - -static int fill_share_info(connection_struct *conn, int snum, int uLevel, - char** buf, int* buflen, - char** stringbuf, int* stringspace, char* baseaddr) -{ - int struct_len; - char* p; - char* p2; - int l2; - int len; - - switch( uLevel ) { - case 0: struct_len = 13; break; - case 1: struct_len = 20; break; - case 2: struct_len = 40; break; - case 91: struct_len = 68; break; - default: return -1; - } - - - if (!buf) - { - len = 0; - if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum)); - if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1; - if (buflen) *buflen = struct_len; - if (stringspace) *stringspace = len; - return struct_len + len; - } - - len = struct_len; - p = *buf; - if ((*buflen) < struct_len) return -1; - if (stringbuf) - { - p2 = *stringbuf; - l2 = *stringspace; - } - else - { - p2 = p + struct_len; - l2 = (*buflen) - struct_len; - } - if (!baseaddr) baseaddr = p; - - push_ascii(p,lp_servicename(snum),13, STR_TERMINATE); - - if (uLevel > 0) - { - int type; - SCVAL(p,13,0); - type = STYPE_DISKTREE; - if (lp_print_ok(snum)) type = STYPE_PRINTQ; - if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC; - SSVAL(p,14,type); /* device type */ - SIVAL(p,16,PTR_DIFF(p2,baseaddr)); - len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2); - } - - if (uLevel > 1) - { - SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */ - SSVALS(p,22,-1); /* max uses */ - SSVAL(p,24,1); /* current uses */ - SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */ - len += CopyAndAdvance(&p2,lp_pathname(snum),&l2); - memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */ - } - - if (uLevel > 2) - { - memset(p+40,0,SHPWLEN+2); - SSVAL(p,50,0); - SIVAL(p,52,0); - SSVAL(p,56,0); - SSVAL(p,58,0); - SIVAL(p,60,0); - SSVAL(p,64,0); - SSVAL(p,66,0); - } - - if (stringbuf) - { - (*buf) = p + struct_len; - (*buflen) -= struct_len; - (*stringbuf) = p2; - (*stringspace) = l2; - } - else - { - (*buf) = p2; - (*buflen) -= len; - } - return len; -} - -static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *netname = skip_string(str2,1); - char *p = skip_string(netname,1); - int uLevel = SVAL(p,0); - int snum = find_service(netname); - - if (snum < 0) return False; - - /* check it's a supported varient */ - if (!prefix_ok(str1,"zWrLh")) return False; - if (!check_share_info(uLevel,str2)) return False; - - *rdata = REALLOC(*rdata,mdrcnt); - p = *rdata; - *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0); - if (*rdata_len < 0) return False; - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); - - return(True); -} - -/**************************************************************************** - View the list of available shares. - - This function is the server side of the NetShareEnum() RAP call. - It fills the return buffer with share names and share comments. - Note that the return buffer normally (in all known cases) allows only - twelve byte strings for share names (plus one for a nul terminator). - Share names longer than 12 bytes must be skipped. - ****************************************************************************/ -static BOOL api_RNetShareEnum( connection_struct *conn, - uint16 vuid, - char *param, - char *data, - int mdrcnt, - int mprcnt, - char **rdata, - char **rparam, - int *rdata_len, - int *rparam_len ) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - char *p2; - int count=lp_numservices(); - int total=0,counted=0; - BOOL missed = False; - int i; - int data_len, fixed_len, string_len; - int f_len = 0, s_len = 0; - - if (!prefix_ok(str1,"WrLeh")) return False; - if (!check_share_info(uLevel,str2)) return False; - - data_len = fixed_len = string_len = 0; - for (i=0;i<count;i++) - if( lp_browseable( i ) - && lp_snum_ok( i ) - && (strlen( lp_servicename( i ) ) < 13) ) /* Maximum name length. */ - { - total++; - data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0); - if (data_len <= buf_len) - { - counted++; - fixed_len += f_len; - string_len += s_len; - } - else - missed = True; - } - *rdata_len = fixed_len + string_len; - *rdata = REALLOC(*rdata,*rdata_len); - memset(*rdata,0,*rdata_len); - - p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ - p = *rdata; - f_len = fixed_len; - s_len = string_len; - for( i = 0; i < count; i++ ) - { - if( lp_browseable( i ) - && lp_snum_ok( i ) - && (strlen( lp_servicename( i ) ) < 13) ) - { - if( fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0 ) - break; - } - } - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,total); - - DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", - counted,total,uLevel, - buf_len,*rdata_len,mdrcnt)); - return(True); -} /* api_RNetShareEnum */ - -/**************************************************************************** - Add a share - ****************************************************************************/ -static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - fstring sharename; - fstring comment; - pstring pathname; - char *command, *cmdname; - unsigned int offset; - int snum; - int res = ERRunsup; - - /* check it's a supported varient */ - if (!prefix_ok(str1, RAP_WShareAdd_REQ)) return False; - if (!check_share_info(uLevel, str2)) return False; - if (uLevel != 2) return False; - - pull_ascii_fstring(sharename, data); - snum = find_service(sharename); - if (snum >= 0) { /* already exists */ - res = ERRfilexists; - goto error_exit; - } - - /* only support disk share adds */ - if (SVAL(data,14) != STYPE_DISKTREE) return False; - - offset = IVAL(data, 16); - if (offset >= mdrcnt) { - res = ERRinvalidparam; - goto error_exit; - } - pull_ascii_fstring(comment, offset? (data+offset) : ""); - - offset = IVAL(data, 26); - if (offset >= mdrcnt) { - res = ERRinvalidparam; - goto error_exit; - } - pull_ascii_pstring(pathname, offset? (data+offset) : ""); - - string_replace(sharename, '"', ' '); - string_replace(pathname, '"', ' '); - string_replace(comment, '"', ' '); - - cmdname = lp_add_share_cmd(); - - if (!cmdname || *cmdname == '\0') return False; - - asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"", - lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment); - - if (command) { - DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command )); - if ((res = smbrun(command, NULL)) != 0) { - DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res )); - SAFE_FREE(command); - res = ERRnoaccess; - goto error_exit; - } else { - SAFE_FREE(command); - message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL); - } - } else return False; - - *rparam_len = 6; - *rparam = REALLOC(*rparam, *rparam_len); - SSVAL(*rparam, 0, NERR_Success); - SSVAL(*rparam, 2, 0); /* converter word */ - SSVAL(*rparam, 4, *rdata_len); - *rdata_len = 0; - - return True; - -error_exit: - *rparam_len = 4; - *rparam = REALLOC(*rparam, *rparam_len); - *rdata_len = 0; - SSVAL(*rparam, 0, res); - SSVAL(*rparam, 2, 0); - return True; - -} - -/**************************************************************************** - view list of groups available - ****************************************************************************/ -static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - int i; - int errflags=0; - int resume_context, cli_buf_size; - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - BOOL ret; - - GROUP_MAP *group_list; - int num_entries; - - if (strcmp(str1,"WrLeh") != 0) - return False; - - /* parameters - * W-> resume context (number of users to skip) - * r -> return parameter pointer to receive buffer - * L -> length of receive buffer - * e -> return parameter number of entries - * h -> return parameter total number of users - */ - if (strcmp("B21",str2) != 0) - return False; - - /* get list of domain groups SID_DOMAIN_GRP=2 */ - become_root(); - ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False); - unbecome_root(); - - if( !ret ) { - DEBUG(3,("api_RNetGroupEnum:failed to get group list")); - return False; - } - - resume_context = SVAL(p,0); - cli_buf_size=SVAL(p+2,0); - DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size)); - - *rdata_len = cli_buf_size; - *rdata = REALLOC(*rdata,*rdata_len); - - p = *rdata; - - for(i=resume_context; i<num_entries; i++) { - char* name=group_list[i].nt_name; - if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) { - /* truncate the name at 21 chars. */ - memcpy(p, name, 21); - DEBUG(10,("adding entry %d group %s\n", i, p)); - p += 21; - } else { - /* set overflow error */ - DEBUG(3,("overflow on entry %d group %s\n", i, name)); - errflags=234; - break; - } - } - - *rdata_len = PTR_DIFF(p,*rdata); - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - SSVAL(*rparam, 0, errflags); - SSVAL(*rparam, 2, 0); /* converter word */ - SSVAL(*rparam, 4, i-resume_context); /* is this right?? */ - SSVAL(*rparam, 6, num_entries); /* is this right?? */ - - return(True); -} - -/******************************************************************* - get groups that a user is a member of - ******************************************************************/ -static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - const char *level_string; - int count=0; - SAM_ACCOUNT *sampw = NULL; - BOOL ret = False; - DOM_GID *gids = NULL; - int num_groups = 0; - int i; - fstring grp_domain; - fstring grp_name; - enum SID_NAME_USE grp_type; - DOM_SID sid, dom_sid; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - - if ( strcmp(str1,"zWrLeh") != 0 ) - return False; - - switch( uLevel ) { - case 0: - level_string = "B21"; - break; - default: - return False; - } - - if (strcmp(level_string,str2) != 0) - return False; - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - - /* Lookup the user information; This should only be one of - our accounts (not remote domains) */ - - pdb_init_sam( &sampw ); - - become_root(); /* ROOT BLOCK */ - - if ( !pdb_getsampwnam(sampw, UserName) ) - goto out; - - /* this next set of code is horribly inefficient, but since - it is rarely called, I'm going to leave it like this since - it easier to follow --jerry */ - - /* get the list of group SIDs */ - - if ( !get_domain_user_groups(conn->mem_ctx, &num_groups, &gids, sampw) ) { - DEBUG(1,("api_NetUserGetGroups: get_domain_user_groups() failed!\n")); - goto out; - } - - /* convert to names (we don't support universal groups so the domain - can only be ours) */ - - sid_copy( &dom_sid, get_global_sam_sid() ); - for (i=0; i<num_groups; i++) { - - /* make the DOM_GID into a DOM_SID and then lookup - the name */ - - sid_copy( &sid, &dom_sid ); - sid_append_rid( &sid, gids[i].g_rid ); - - if ( lookup_sid(&sid, grp_domain, grp_name, &grp_type) ) { - pstrcpy(p, grp_name); - p += 21; - count++; - } - } - - *rdata_len = PTR_DIFF(p,*rdata); - - SSVAL(*rparam,4,count); /* is this right?? */ - SSVAL(*rparam,6,count); /* is this right?? */ - - ret = True; - -out: - unbecome_root(); /* END ROOT BLOCK */ - - pdb_free_sam( &sampw ); - - return ret; -} - -/******************************************************************* - get all users - ******************************************************************/ -static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - SAM_ACCOUNT *pwd=NULL; - int count_sent=0; - int count_total=0; - int errflags=0; - int resume_context, cli_buf_size; - - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - - if (strcmp(str1,"WrLeh") != 0) - return False; - /* parameters - * W-> resume context (number of users to skip) - * r -> return parameter pointer to receive buffer - * L -> length of receive buffer - * e -> return parameter number of entries - * h -> return parameter total number of users - */ - - resume_context = SVAL(p,0); - cli_buf_size=SVAL(p+2,0); - DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size)); - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - if (strcmp("B21",str2) != 0) - return False; - - *rdata_len = cli_buf_size; - *rdata = REALLOC(*rdata,*rdata_len); - - p = *rdata; - - /* to get user list enumerations for NetUserEnum in B21 format */ - pdb_init_sam(&pwd); - - /* Open the passgrp file - not for update. */ - become_root(); - if(!pdb_setsampwent(False)) { - DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n")); - unbecome_root(); - return False; - } - errflags=NERR_Success; - - while ( pdb_getsampwent(pwd) ) { - const char *name=pdb_get_username(pwd); - if ((name) && (*(name+strlen(name)-1)!='$')) { - count_total++; - if(count_total>=resume_context) { - if( ((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21) ) { - pstrcpy(p,name); - DEBUG(10,("api_RNetUserEnum:adding entry %d username %s\n",count_sent,p)); - p += 21; - count_sent++; - } else { - /* set overflow error */ - DEBUG(10,("api_RNetUserEnum:overflow on entry %d username %s\n",count_sent,name)); - errflags=234; - break; - } - } - } - } ; - - pdb_endsampwent(); - unbecome_root(); - - pdb_free_sam(&pwd); - - *rdata_len = PTR_DIFF(p,*rdata); - - SSVAL(*rparam,0,errflags); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,count_sent); /* is this right?? */ - SSVAL(*rparam,6,count_total); /* is this right?? */ - - return True; -} - - - -/**************************************************************************** - get the time of day info - ****************************************************************************/ -static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *p; - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 21; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - - { - struct tm *t; - time_t unixdate = time(NULL); - - put_dos_date3(p,0,unixdate); /* this is the time that is looked at - by NT in a "net time" operation, - it seems to ignore the one below */ - - /* the client expects to get localtime, not GMT, in this bit - (I think, this needs testing) */ - t = LocalTime(&unixdate); - - SIVAL(p,4,0); /* msecs ? */ - 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 */ - SCVAL(p,16,t->tm_mday); - SCVAL(p,17,t->tm_mon + 1); - SSVAL(p,18,1900+t->tm_year); - SCVAL(p,20,t->tm_wday); - } - - - return(True); -} - -/**************************************************************************** - Set the user password. -*****************************************************************************/ - -static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *p = skip_string(param+2,2); - fstring user; - fstring pass1,pass2; - - pull_ascii_fstring(user,p); - - p = skip_string(p,1); - - memset(pass1,'\0',sizeof(pass1)); - memset(pass2,'\0',sizeof(pass2)); - memcpy(pass1,p,16); - memcpy(pass2,p+16,16); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_badpass); - SSVAL(*rparam,2,0); /* converter word */ - - DEBUG(3,("Set password for <%s>\n",user)); - - /* - * Attempt to verify the old password against smbpasswd entries - * Win98 clients send old and new password in plaintext for this call. - */ - - { - auth_serversupplied_info *server_info = NULL; - DATA_BLOB password = data_blob(pass1, strlen(pass1)+1); - - if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) { - - become_root(); - if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False))) { - SSVAL(*rparam,0,NERR_Success); - } - unbecome_root(); - - free_server_info(&server_info); - } - data_blob_clear_free(&password); - } - - /* - * If the plaintext change failed, attempt - * the old encrypted method. NT will generate this - * after trying the samr method. Note that this - * method is done as a last resort as this - * password change method loses the NT password hash - * and cannot change the UNIX password as no plaintext - * is received. - */ - - if(SVAL(*rparam,0) != NERR_Success) { - SAM_ACCOUNT *hnd = NULL; - - if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) { - become_root(); - if (change_lanman_password(hnd,(uchar *)pass2)) { - SSVAL(*rparam,0,NERR_Success); - } - unbecome_root(); - pdb_free_sam(&hnd); - } - } - - memset((char *)pass1,'\0',sizeof(fstring)); - memset((char *)pass2,'\0',sizeof(fstring)); - - return(True); -} - -/**************************************************************************** - Set the user password (SamOEM version - gets plaintext). -****************************************************************************/ - -static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - fstring user; - char *p = param + 2; - *rparam_len = 2; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_badpass); - - /* - * Check the parameter definition is correct. - */ - - if(!strequal(param + 2, "zsT")) { - DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2)); - return False; - } - p = skip_string(p, 1); - - if(!strequal(p, "B516B16")) { - DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p)); - return False; - } - p = skip_string(p,1); - p += pull_ascii_fstring(user,p); - - DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user)); - - /* - * Pass the user through the NT -> unix user mapping - * function. - */ - - (void)map_username(user); - - if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))) { - SSVAL(*rparam,0,NERR_Success); - } - - return(True); -} - -/**************************************************************************** - delete a print job - Form: <W> <> - ****************************************************************************/ -static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - int function = SVAL(param,0); - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - uint32 jobid; - int snum; - int errcode; - extern struct current_user current_user; - WERROR werr = WERR_OK; - - if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) - return False; - - /* check it's a supported varient */ - if (!(strcsequal(str1,"W") && strcsequal(str2,""))) - return(False); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - *rdata_len = 0; - - if (!print_job_exists(snum, jobid)) { - errcode = NERR_JobNotFound; - goto out; - } - - errcode = NERR_notsupported; - - switch (function) { - case 81: /* delete */ - if (print_job_delete(¤t_user, snum, jobid, &werr)) - errcode = NERR_Success; - break; - case 82: /* pause */ - if (print_job_pause(¤t_user, snum, jobid, &werr)) - errcode = NERR_Success; - break; - case 83: /* resume */ - if (print_job_resume(¤t_user, snum, 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 */ - - return(True); -} - -/**************************************************************************** - Purge a print queue - or pause or resume it. - ****************************************************************************/ -static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - int function = SVAL(param,0); - char *str1 = param+2; - char *str2 = skip_string(str1,1); - 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 */ - if (!(strcsequal(str1,"z") && strcsequal(str2,""))) - return(False); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - *rdata_len = 0; - - snum = print_queue_snum(QueueName); - - if (snum == -1) { - errcode = NERR_JobNotFound; - goto out; - } - - switch (function) { - case 74: /* Pause queue */ - if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success; - break; - case 75: /* Resume queue */ - if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success; - break; - case 103: /* Purge */ - 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 */ - - return(True); -} - - -/**************************************************************************** - set the property of a print job (undocumented?) - ? function = 0xb -> set name of print job - ? function = 0x6 -> move print job up/down - Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> - or <WWsTP> <WB21BB16B10zWWzDDz> -****************************************************************************/ -static int check_printjob_info(struct pack_desc* desc, - int uLevel, char* id) -{ - desc->subformat = NULL; - switch( uLevel ) { - case 0: desc->format = "W"; break; - case 1: desc->format = "WB21BB16B10zWWzDDz"; break; - case 2: desc->format = "WWzWWDDzz"; break; - case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break; - case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break; - default: return False; - } - if (strcmp(desc->format,id) != 0) return False; - return True; -} - -static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - struct pack_desc desc; - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - uint32 jobid; - int snum; - int uLevel = SVAL(p,2); - int function = SVAL(p,4); - int place, errcode; - - if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) - return False; - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - /* check it's a supported varient */ - if ((strcmp(str1,"WWsTP")) || - (!check_printjob_info(&desc,uLevel,str2))) - return(False); - - if (!print_job_exists(snum, jobid)) { - errcode=NERR_JobNotFound; - goto out; - } - - errcode = NERR_notsupported; - - switch (function) { - case 0x6: - /* change job place in the queue, - data gives the new place */ - place = SVAL(data,0); - if (print_job_set_place(snum, jobid, place)) { - errcode=NERR_Success; - } - break; - - case 0xb: - /* change print job name, data gives the name */ - if (print_job_set_name(snum, jobid, data)) { - errcode=NERR_Success; - } - break; - - default: - return False; - } - - out: - SSVALS(*rparam,0,errcode); - SSVAL(*rparam,2,0); /* converter word */ - - return(True); -} - - -/**************************************************************************** - get info about the server - ****************************************************************************/ -static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - char *p2; - int struct_len; - - DEBUG(4,("NetServerGetInfo level %d\n",uLevel)); - - /* check it's a supported varient */ - if (!prefix_ok(str1,"WrLh")) return False; - switch( uLevel ) { - case 0: - if (strcmp(str2,"B16") != 0) return False; - struct_len = 16; - break; - case 1: - if (strcmp(str2,"B16BBDz") != 0) return False; - struct_len = 26; - break; - case 2: - if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz") - != 0) return False; - struct_len = 134; - break; - case 3: - if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") - != 0) return False; - struct_len = 144; - break; - case 20: - if (strcmp(str2,"DN") != 0) return False; - struct_len = 6; - break; - case 50: - if (strcmp(str2,"B16BBDzWWzzz") != 0) return False; - struct_len = 42; - break; - default: return False; - } - - *rdata_len = mdrcnt; - *rdata = REALLOC(*rdata,*rdata_len); - - p = *rdata; - p2 = p + struct_len; - if (uLevel != 20) { - srvstr_push(NULL, p,local_machine,16, - STR_ASCII|STR_UPPER|STR_TERMINATE); - } - p += 16; - if (uLevel > 0) - { - struct srv_info_struct *servers=NULL; - int i,count; - pstring comment; - uint32 servertype= lp_default_server_announce(); - - push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE); - - if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) { - for (i=0;i<count;i++) { - if (strequal(servers[i].name,local_machine)) { - servertype = servers[i].type; - push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE); - } - } - } - SAFE_FREE(servers); - - SCVAL(p,0,lp_major_announce_version()); - SCVAL(p,1,lp_minor_announce_version()); - SIVAL(p,2,servertype); - - if (mdrcnt == struct_len) { - SIVAL(p,6,0); - } else { - SIVAL(p,6,PTR_DIFF(p2,*rdata)); - standard_sub_conn(conn,comment,sizeof(comment)); - StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0)); - p2 = skip_string(p2,1); - } - } - if (uLevel > 1) - { - return False; /* not yet implemented */ - } - - *rdata_len = PTR_DIFF(p2,*rdata); - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); - - return(True); -} - - -/**************************************************************************** - get info about the server - ****************************************************************************/ -static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char *p2; - extern userdom_struct current_user_info; - int level = SVAL(p,0); - - DEBUG(4,("NetWkstaGetInfo level %d\n",level)); - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) - return(False); - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - p2 = p + 22; - - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ - pstrcpy(p2,local_machine); - strupper_m(p2); - p2 = skip_string(p2,1); - p += 4; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); - pstrcpy(p2,current_user_info.smb_name); - p2 = skip_string(p2,1); - p += 4; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ - pstrcpy(p2,lp_workgroup()); - strupper_m(p2); - p2 = skip_string(p2,1); - p += 4; - - SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */ - SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */ - p += 2; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); - pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */ - p2 = skip_string(p2,1); - p += 4; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */ - pstrcpy(p2,""); - p2 = skip_string(p2,1); - p += 4; - - *rdata_len = PTR_DIFF(p2,*rdata); - - SSVAL(*rparam,4,*rdata_len); - - return(True); -} - -/**************************************************************************** - get info about a user - - struct user_info_11 { - char usri11_name[21]; 0-20 - char usri11_pad; 21 - char *usri11_comment; 22-25 - char *usri11_usr_comment; 26-29 - unsigned short usri11_priv; 30-31 - unsigned long usri11_auth_flags; 32-35 - long usri11_password_age; 36-39 - char *usri11_homedir; 40-43 - char *usri11_parms; 44-47 - long usri11_last_logon; 48-51 - long usri11_last_logoff; 52-55 - unsigned short usri11_bad_pw_count; 56-57 - unsigned short usri11_num_logons; 58-59 - char *usri11_logon_server; 60-63 - unsigned short usri11_country_code; 64-65 - char *usri11_workstations; 66-69 - unsigned long usri11_max_storage; 70-73 - unsigned short usri11_units_per_week; 74-75 - unsigned char *usri11_logon_hours; 76-79 - unsigned short usri11_code_page; 80-81 - }; - -where: - - usri11_name specifies the user name for which information is retireved - - usri11_pad aligns the next data structure element to a word boundary - - usri11_comment is a null terminated ASCII comment - - usri11_user_comment is a null terminated ASCII comment about the user - - usri11_priv specifies the level of the privilege assigned to the user. - The possible values are: - -Name Value Description -USER_PRIV_GUEST 0 Guest privilege -USER_PRIV_USER 1 User privilege -USER_PRV_ADMIN 2 Administrator privilege - - usri11_auth_flags specifies the account operator privileges. The - possible values are: - -Name Value Description -AF_OP_PRINT 0 Print operator - - -Leach, Naik [Page 28] - - - -INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 - - -AF_OP_COMM 1 Communications operator -AF_OP_SERVER 2 Server operator -AF_OP_ACCOUNTS 3 Accounts operator - - - usri11_password_age specifies how many seconds have elapsed since the - password was last changed. - - usri11_home_dir points to a null terminated ASCII string that contains - the path name of the user's home directory. - - usri11_parms points to a null terminated ASCII string that is set - aside for use by applications. - - usri11_last_logon specifies the time when the user last logged on. - This value is stored as the number of seconds elapsed since - 00:00:00, January 1, 1970. - - usri11_last_logoff specifies the time when the user last logged off. - This value is stored as the number of seconds elapsed since - 00:00:00, January 1, 1970. A value of 0 means the last logoff - time is unknown. - - usri11_bad_pw_count specifies the number of incorrect passwords - entered since the last successful logon. - - usri11_log1_num_logons specifies the number of times this user has - logged on. A value of -1 means the number of logons is unknown. - - usri11_logon_server points to a null terminated ASCII string that - contains the name of the server to which logon requests are sent. - A null string indicates logon requests should be sent to the - domain controller. - - usri11_country_code specifies the country code for the user's language - of choice. - - usri11_workstations points to a null terminated ASCII string that - contains the names of workstations the user may log on from. - There may be up to 8 workstations, with the names separated by - commas. A null strings indicates there are no restrictions. - - usri11_max_storage specifies the maximum amount of disk space the user - can occupy. A value of 0xffffffff indicates there are no - restrictions. - - usri11_units_per_week specifies the equal number of time units into - which a week is divided. This value must be equal to 168. - - usri11_logon_hours points to a 21 byte (168 bits) string that - specifies the time during which the user can log on. Each bit - represents one unique hour in a week. The first bit (bit 0, word - 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is - - - -Leach, Naik [Page 29] - - - -INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 - - - Sunday, 1:00 to 1:59 and so on. A null pointer indicates there - are no restrictions. - - usri11_code_page specifies the code page for the user's language of - choice - -All of the pointers in this data structure need to be treated -specially. The pointer is a 32 bit pointer. The higher 16 bits need -to be ignored. The converter word returned in the parameters section -needs to be subtracted from the lower 16 bits to calculate an offset -into the return buffer where this ASCII string resides. - -There is no auxiliary data in the response. - - ****************************************************************************/ - -#define usri11_name 0 -#define usri11_pad 21 -#define usri11_comment 22 -#define usri11_usr_comment 26 -#define usri11_full_name 30 -#define usri11_priv 34 -#define usri11_auth_flags 36 -#define usri11_password_age 40 -#define usri11_homedir 44 -#define usri11_parms 48 -#define usri11_last_logon 52 -#define usri11_last_logoff 56 -#define usri11_bad_pw_count 60 -#define usri11_num_logons 62 -#define usri11_logon_server 64 -#define usri11_country_code 68 -#define usri11_workstations 70 -#define usri11_max_storage 74 -#define usri11_units_per_week 78 -#define usri11_logon_hours 80 -#define usri11_code_page 84 -#define usri11_end 86 - -#define USER_PRIV_GUEST 0 -#define USER_PRIV_USER 1 -#define USER_PRIV_ADMIN 2 - -#define AF_OP_PRINT 0 -#define AF_OP_COMM 1 -#define AF_OP_SERVER 2 -#define AF_OP_ACCOUNTS 3 - - -static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - char *p2; - const char *level_string; - - /* get NIS home of a previously validated user - simeon */ - /* With share level security vuid will always be zero. - Don't depend on vuser being non-null !!. JRA */ - user_struct *vuser = get_valid_user_struct(vuid); - if(vuser != NULL) - DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, - vuser->user.unix_name)); - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - - DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel)); - - /* check it's a supported variant */ - if (strcmp(str1,"zWrLh") != 0) return False; - switch( uLevel ) - { - case 0: level_string = "B21"; break; - case 1: level_string = "B21BB16DWzzWz"; break; - case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break; - case 10: level_string = "B21Bzzz"; break; - case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break; - default: return False; - } - - if (strcmp(level_string,str2) != 0) return False; - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - p2 = p + usri11_end; - - memset(p,0,21); - fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */ - - if (uLevel > 0) - { - SCVAL(p,usri11_pad,0); /* padding - 1 byte */ - *p2 = 0; - } - if (uLevel >= 10) - { - SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */ - pstrcpy(p2,"Comment"); - p2 = skip_string(p2,1); - - SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */ - pstrcpy(p2,"UserComment"); - p2 = skip_string(p2,1); - - /* EEK! the cifsrap.txt doesn't have this in!!!! */ - SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */ - pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName)); - p2 = skip_string(p2,1); - } - - if (uLevel == 11) /* modelled after NTAS 3.51 reply */ - { - SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */ - SIVALS(p,usri11_password_age,-1); /* password age */ - SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */ - pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : ""); - p2 = skip_string(p2,1); - SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */ - pstrcpy(p2,""); - p2 = skip_string(p2,1); - SIVAL(p,usri11_last_logon,0); /* last logon */ - SIVAL(p,usri11_last_logoff,0); /* last logoff */ - SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */ - SSVALS(p,usri11_num_logons,-1); /* num logons */ - SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */ - pstrcpy(p2,"\\\\*"); - p2 = skip_string(p2,1); - SSVAL(p,usri11_country_code,0); /* country code */ - - SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */ - pstrcpy(p2,""); - p2 = skip_string(p2,1); - - SIVALS(p,usri11_max_storage,-1); /* max storage */ - SSVAL(p,usri11_units_per_week,168); /* units per week */ - SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */ - - /* a simple way to get logon hours at all times. */ - memset(p2,0xff,21); - SCVAL(p2,21,0); /* fix zero termination */ - p2 = skip_string(p2,1); - - SSVAL(p,usri11_code_page,0); /* code page */ - } - if (uLevel == 1 || uLevel == 2) - { - memset(p+22,' ',16); /* password */ - SIVALS(p,38,-1); /* password age */ - SSVAL(p,42, - conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ - pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : ""); - p2 = skip_string(p2,1); - SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ - *p2++ = 0; - SSVAL(p,52,0); /* flags */ - SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */ - pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : ""); - p2 = skip_string(p2,1); - if (uLevel == 2) - { - SIVAL(p,60,0); /* auth_flags */ - SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */ - pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName)); - p2 = skip_string(p2,1); - SIVAL(p,68,0); /* urs_comment */ - SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */ - pstrcpy(p2,""); - p2 = skip_string(p2,1); - SIVAL(p,76,0); /* workstations */ - SIVAL(p,80,0); /* last_logon */ - SIVAL(p,84,0); /* last_logoff */ - SIVALS(p,88,-1); /* acct_expires */ - SIVALS(p,92,-1); /* max_storage */ - SSVAL(p,96,168); /* units_per_week */ - SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */ - memset(p2,-1,21); - p2 += 21; - SSVALS(p,102,-1); /* bad_pw_count */ - SSVALS(p,104,-1); /* num_logons */ - SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */ - pstrcpy(p2,"\\\\%L"); - standard_sub_conn(conn, p2,0); - p2 = skip_string(p2,1); - SSVAL(p,110,49); /* country_code */ - SSVAL(p,112,860); /* code page */ - } - } - - *rdata_len = PTR_DIFF(p2,*rdata); - - SSVAL(*rparam,4,*rdata_len); /* is this right?? */ - - return(True); -} - -static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - struct pack_desc desc; - char* name; - /* With share level security vuid will always be zero. - Don't depend on vuser being non-null !!. JRA */ - user_struct *vuser = get_valid_user_struct(vuid); - if(vuser != NULL) - DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, - vuser->user.unix_name)); - - uLevel = SVAL(p,0); - name = p + 2; - - memset((char *)&desc,'\0',sizeof(desc)); - - DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name)); - - /* check it's a supported varient */ - if (strcmp(str1,"OOWb54WrLh") != 0) return False; - if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False; - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.subformat = NULL; - desc.format = str2; - - if (init_package(&desc,1,0)) - { - PACKI(&desc,"W",0); /* code */ - PACKS(&desc,"B21",name); /* eff. name */ - PACKS(&desc,"B",""); /* pad */ - PACKI(&desc,"W", - conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - PACKI(&desc,"D",0); /* auth flags XXX */ - PACKI(&desc,"W",0); /* num logons */ - PACKI(&desc,"W",0); /* bad pw count */ - PACKI(&desc,"D",0); /* last logon */ - PACKI(&desc,"D",-1); /* last logoff */ - PACKI(&desc,"D",-1); /* logoff time */ - PACKI(&desc,"D",-1); /* kickoff time */ - PACKI(&desc,"D",0); /* password age */ - PACKI(&desc,"D",0); /* password can change */ - PACKI(&desc,"D",-1); /* password must change */ - { - fstring mypath; - fstrcpy(mypath,"\\\\"); - fstrcat(mypath,local_machine); - strupper_m(mypath); - PACKS(&desc,"z",mypath); /* computer */ - } - PACKS(&desc,"z",lp_workgroup());/* domain */ - - PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */ - - PACKI(&desc,"D",0x00000000); /* reserved */ - } - - *rdata_len = desc.usedlen; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode)); - return(True); -} - - -/**************************************************************************** - api_WAccessGetUserPerms - ****************************************************************************/ -static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *user = skip_string(str2,1); - char *resource = skip_string(user,1); - - DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource)); - - /* check it's a supported varient */ - if (strcmp(str1,"zzh") != 0) return False; - if (strcmp(str2,"") != 0) return False; - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,0); /* errorcode */ - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,0x7f); /* permission flags */ - - return(True); -} - -/**************************************************************************** - api_WPrintJobEnumerate - ****************************************************************************/ -static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int count; - int i; - int snum; - uint32 jobid; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - char *tmpdata=NULL; - - uLevel = SVAL(p,2); - - memset((char *)&desc,'\0',sizeof(desc)); - memset((char *)&status,'\0',sizeof(status)); - - DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0))); - - /* check it's a supported varient */ - if (strcmp(str1,"WWrLh") != 0) return False; - if (!check_printjob_info(&desc,uLevel,str2)) return False; - - if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid)) - return False; - - if (snum < 0 || !VALID_SNUM(snum)) return(False); - - count = print_queue_status(snum,&queue,&status); - for (i = 0; i < count; i++) { - if (queue[i].job == jobid) break; - } - - if (mdrcnt > 0) { - *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - } else { - /* - * Don't return data but need to get correct length - * init_package will return wrong size if buflen=0 - */ - desc.buflen = getlen(desc.format); - desc.base = tmpdata = (char *)malloc ( desc.buflen ); - } - - if (init_package(&desc,1,0)) { - if (i < count) { - fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i); - *rdata_len = desc.usedlen; - } - else { - desc.errcode = NERR_JobNotFound; - *rdata_len = 0; - } - } - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - SAFE_FREE(queue); - SAFE_FREE(tmpdata); - - DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char* name = p; - int uLevel; - int count; - int i, succnt=0; - int snum; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - - memset((char *)&desc,'\0',sizeof(desc)); - memset((char *)&status,'\0',sizeof(status)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); - - /* check it's a supported variant */ - if (strcmp(str1,"zWrLeh") != 0) return False; - if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */ - if (!check_printjob_info(&desc,uLevel,str2)) return False; - - snum = lp_servicenumber(name); - if (snum < 0 && pcap_printername_ok(name,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(name,pnum); - snum = lp_servicenumber(name); - } - } - - if (snum < 0 || !VALID_SNUM(snum)) return(False); - - count = print_queue_status(snum,&queue,&status); - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - - if (init_package(&desc,count,0)) { - succnt = 0; - for (i = 0; i < count; i++) { - fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i); - if (desc.errcode == NERR_Success) succnt = i+1; - } - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,count); - - SAFE_FREE(queue); - - DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); - return(True); -} - -static int check_printdest_info(struct pack_desc* desc, - int uLevel, char* id) -{ - desc->subformat = NULL; - switch( uLevel ) { - case 0: desc->format = "B9"; break; - case 1: desc->format = "B9B21WWzW"; break; - case 2: desc->format = "z"; break; - case 3: desc->format = "zzzWWzzzWW"; break; - default: return False; - } - if (strcmp(desc->format,id) != 0) return False; - return True; -} - -static void fill_printdest_info(connection_struct *conn, int snum, int uLevel, - struct pack_desc* desc) -{ - char buf[100]; - strncpy(buf,SERVICE(snum),sizeof(buf)-1); - buf[sizeof(buf)-1] = 0; - strupper_m(buf); - if (uLevel <= 1) { - PACKS(desc,"B9",buf); /* szName */ - if (uLevel == 1) { - PACKS(desc,"B21",""); /* szUserName */ - PACKI(desc,"W",0); /* uJobId */ - PACKI(desc,"W",0); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKI(desc,"W",0); /* time */ - } - } - if (uLevel == 2 || uLevel == 3) { - PACKS(desc,"z",buf); /* pszPrinterName */ - if (uLevel == 3) { - PACKS(desc,"z",""); /* pszUserName */ - PACKS(desc,"z",""); /* pszLogAddr */ - PACKI(desc,"W",0); /* uJobId */ - PACKI(desc,"W",0); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKS(desc,"z",""); /* pszComment */ - PACKS(desc,"z","NULL"); /* pszDrivers */ - PACKI(desc,"W",0); /* time */ - PACKI(desc,"W",0); /* pad1 */ - } - } -} - -static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char* PrinterName = p; - int uLevel; - struct pack_desc desc; - int snum; - char *tmpdata=NULL; - - memset((char *)&desc,'\0',sizeof(desc)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName)); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLh") != 0) return False; - if (!check_printdest_info(&desc,uLevel,str2)) return False; - - snum = lp_servicenumber(PrinterName); - if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(PrinterName,pnum); - snum = lp_servicenumber(PrinterName); - } - } - - if (snum < 0) { - *rdata_len = 0; - desc.errcode = NERR_DestNotFound; - desc.neededlen = 0; - } - else { - if (mdrcnt > 0) { - *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - } else { - /* - * Don't return data but need to get correct length - * init_package will return wrong size if buflen=0 - */ - desc.buflen = getlen(desc.format); - desc.base = tmpdata = (char *)malloc ( desc.buflen ); - } - if (init_package(&desc,1,0)) { - fill_printdest_info(conn,snum,uLevel,&desc); - } - *rdata_len = desc.usedlen; - } - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); - SAFE_FREE(tmpdata); - return(True); -} - -static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int queuecnt; - int i, n, succnt=0; - struct pack_desc desc; - int services = lp_numservices(); - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (!check_printdest_info(&desc,uLevel,str2)) return False; - - queuecnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) - queuecnt++; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,queuecnt,0)) { - succnt = 0; - n = 0; - for (i = 0; i < services; i++) { - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - fill_printdest_info(conn,i,uLevel,&desc); - n++; - if (desc.errcode == NERR_Success) succnt = n; - } - } - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,queuecnt); - - DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int succnt; - struct pack_desc desc; - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B41") != 0) return False; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B41","NULL"); - } - - succnt = (desc.errcode == NERR_Success ? 1 : 0); - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); - - DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int succnt; - struct pack_desc desc; - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B13") != 0) return False; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B13","lpd"); - } - - succnt = (desc.errcode == NERR_Success ? 1 : 0); - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); - - DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - int succnt; - struct pack_desc desc; - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B9") != 0) return False; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - memset((char *)&desc,'\0',sizeof(desc)); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B13","lp0"); - } - - succnt = (desc.errcode == NERR_Success ? 1 : 0); - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); - - DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode)); - return(True); -} - - -/**************************************************************************** - List open sessions - ****************************************************************************/ -static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) - -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - struct pack_desc desc; - struct sessionid *session_list; - int i, num_sessions; - - memset((char *)&desc,'\0',sizeof(desc)); - - uLevel = SVAL(p,0); - - DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel)); - DEBUG(7,("RNetSessionEnum req string=%s\n",str1)); - DEBUG(7,("RNetSessionEnum ret string=%s\n",str2)); - - /* check it's a supported varient */ - if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False; - if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False; - - num_sessions = list_sessions(&session_list); - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - memset((char *)&desc,'\0',sizeof(desc)); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (!init_package(&desc,num_sessions,0)) { - return False; - } - - for(i=0; i<num_sessions; i++) { - PACKS(&desc, "z", session_list[i].remote_machine); - PACKS(&desc, "z", session_list[i].username); - PACKI(&desc, "W", 1); /* num conns */ - PACKI(&desc, "W", 0); /* num opens */ - PACKI(&desc, "W", 1); /* num users */ - PACKI(&desc, "D", 0); /* session time */ - PACKI(&desc, "D", 0); /* idle time */ - PACKI(&desc, "D", 0); /* flags */ - PACKS(&desc, "z", "Unknown Client"); /* client type string */ - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); /* converter */ - SSVAL(*rparam,4,num_sessions); /* count */ - - DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode)); - return True; -} - - -/**************************************************************************** - The buffer was too small - ****************************************************************************/ - -static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - *rparam_len = MIN(*rparam_len,mprcnt); - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_BufTooSmall); - - DEBUG(3,("Supplied buffer too small in API command\n")); - - return(True); -} - - -/**************************************************************************** - The request is not supported - ****************************************************************************/ - -static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_notsupported); - SSVAL(*rparam,2,0); /* converter word */ - - DEBUG(3,("Unsupported API command\n")); - - return(True); -} - - - - -static const struct -{ - const char *name; - int id; - BOOL (*fn)(connection_struct *,uint16,char *,char *, - int,int,char **,char **,int *,int *); - BOOL auth_user; /* Deny anonymous access? */ -} api_commands[] = { - {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True}, - {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo}, - {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd}, - {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True}, - {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo}, - {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True}, - {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True}, - {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True}, - {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo}, - {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups}, - {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo}, - {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True}, - {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo}, - {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl}, - {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl}, - {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate}, - {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo}, - {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel}, - {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel}, - {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel}, - {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum}, - {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo}, - {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD}, - {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl}, - {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */ - {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms}, - {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword}, - {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon}, - {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo}, - {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum}, - {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum}, - {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum}, - {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */ - {NULL, -1, api_Unsupported}}; - -/* The following RAP calls are not implemented by Samba: - - RAP_WFileEnum2 - anon not OK -*/ - -/**************************************************************************** - Handle remote api calls - ****************************************************************************/ - -int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params, - int tdscnt,int tpscnt,int mdrcnt,int mprcnt) -{ - int api_command; - char *rdata = NULL; - char *rparam = NULL; - int rdata_len = 0; - int rparam_len = 0; - BOOL reply=False; - int i; - - if (!params) { - DEBUG(0,("ERROR: NULL params in api_reply()\n")); - return 0; - } - - api_command = SVAL(params,0); - - DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n", - api_command, - params+2, - skip_string(params+2,1), - tdscnt,tpscnt,mdrcnt,mprcnt)); - - for (i=0;api_commands[i].name;i++) { - if (api_commands[i].id == api_command && api_commands[i].fn) { - DEBUG(3,("Doing %s\n",api_commands[i].name)); - break; - } - } - - /* Check whether this api call can be done anonymously */ - - if (api_commands[i].auth_user && lp_restrict_anonymous()) { - user_struct *user = get_valid_user_struct(vuid); - - if (!user || user->guest) - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - - rdata = (char *)malloc(1024); - if (rdata) - memset(rdata,'\0',1024); - - rparam = (char *)malloc(1024); - if (rparam) - memset(rparam,'\0',1024); - - if(!rdata || !rparam) { - DEBUG(0,("api_reply: malloc fail !\n")); - return -1; - } - - reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - - - if (rdata_len > mdrcnt || - rparam_len > mprcnt) { - reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - } - - /* if we get False back then it's actually unsupported */ - if (!reply) - api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - - send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False); - - SAFE_FREE(rdata); - SAFE_FREE(rparam); - - return -1; -} diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c deleted file mode 100644 index c5d7582c033..00000000000 --- a/source/smbd/mangle.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Name mangling interface - Copyright (C) Andrew Tridgell 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -static struct mangle_fns *mangle_fns; - -/* this allows us to add more mangling backends */ -static const struct { - const char *name; - struct mangle_fns *(*init_fn)(void); -} mangle_backends[] = { - { "hash", mangle_hash_init }, - { "hash2", mangle_hash2_init }, - /*{ "tdb", mangle_tdb_init }, */ - { NULL, NULL } -}; - -/* - initialise the mangling subsystem -*/ -static void mangle_init(void) -{ - int i; - char *method; - - if (mangle_fns) - return; - - method = lp_mangling_method(); - - /* find the first mangling method that manages to initialise and - matches the "mangling method" parameter */ - for (i=0; mangle_backends[i].name && !mangle_fns; i++) { - if (!method || !*method || strcmp(method, mangle_backends[i].name) == 0) { - mangle_fns = mangle_backends[i].init_fn(); - } - } - - if (!mangle_fns) { - DEBUG(0,("Failed to initialise mangling system '%s'\n", method)); - exit_server("mangling init failed"); - } -} - - -/* - reset the cache. This is called when smb.conf has been reloaded -*/ -void mangle_reset_cache(void) -{ - mangle_init(); - - mangle_fns->reset(); -} - -/* - see if a filename has come out of our mangling code -*/ -BOOL mangle_is_mangled(const char *s) -{ - return mangle_fns->is_mangled(s); -} - -/* - see if a filename matches the rules of a 8.3 filename -*/ -BOOL mangle_is_8_3(const char *fname, BOOL check_case) -{ - return mangle_fns->is_8_3(fname, check_case, False); -} - -BOOL mangle_is_8_3_wildcards(const char *fname, BOOL check_case) -{ - return mangle_fns->is_8_3(fname, check_case, True); -} - -/* - try to reverse map a 8.3 name to the original filename. This doesn't have to - always succeed, as the directory handling code in smbd will scan the directory - looking for a matching name if it doesn't. It should succeed most of the time - or there will be a huge performance penalty -*/ -BOOL mangle_check_cache(char *s) -{ - return mangle_fns->check_cache(s); -} - -/* - map a long filename to a 8.3 name. - */ - -void mangle_map(pstring OutName, BOOL need83, BOOL cache83, int snum) -{ - /* name mangling can be disabled for speed, in which case - we just truncate the string */ - if (!lp_manglednames(snum)) { - if (need83) { - string_truncate(OutName, 12); - } - return; - } - - /* invoke the inane "mangled map" code */ - mangle_map_filename(OutName, snum); - mangle_fns->name_map(OutName, need83, cache83); -} diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c deleted file mode 100644 index 16722ae6e9d..00000000000 --- a/source/smbd/mangle_hash.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Name mangling - Copyright (C) Andrew Tridgell 1992-2002 - Copyright (C) Simo Sorce 2001 - Copyright (C) Andrew Bartlett 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -/* -------------------------------------------------------------------------- ** - * Notable problems... - * - * March/April 1998 CRH - * - Many of the functions in this module overwrite string buffers passed to - * them. This causes a variety of problems and is, generally speaking, - * dangerous and scarry. See the kludge notes in name_map() - * below. - * - It seems that something is calling name_map() twice. The - * first call is probably some sort of test. Names which contain - * illegal characters are being doubly mangled. I'm not sure, but - * I'm guessing the problem is in server.c. - * - * -------------------------------------------------------------------------- ** - */ - -/* -------------------------------------------------------------------------- ** - * History... - * - * March/April 1998 CRH - * Updated a bit. Rewrote is_mangled() to be a bit more selective. - * Rewrote the mangled name cache. Added comments here and there. - * &c. - * -------------------------------------------------------------------------- ** - */ - -#include "includes.h" - - -/* -------------------------------------------------------------------------- ** - * External Variables... - */ - -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. */ - -/* -------------------------------------------------------------------------- ** - * Other stuff... - * - * magic_char - This is the magic char used for mangling. It's - * global. There is a call to lp_magicchar() in server.c - * that is used to override the initial value. - * - * MANGLE_BASE - This is the number of characters we use for name mangling. - * - * basechars - The set characters used for name mangling. This - * is static (scope is this file only). - * - * mangle() - Macro used to select a character from basechars (i.e., - * mangle(n) will return the nth digit, modulo MANGLE_BASE). - * - * chartest - array 0..255. The index range is the set of all possible - * values of a byte. For each byte value, the content is a - * two nibble pair. See BASECHAR_MASK and ILLEGAL_MASK, - * below. - * - * ct_initialized - False until the chartest array has been initialized via - * a call to init_chartest(). - * - * BASECHAR_MASK - Masks the upper nibble of a one-byte value. - * - * ILLEGAL_MASK - Masks the lower nibble of a one-byte value. - * - * isbasecahr() - Given a character, check the chartest array to see - * if that character is in the basechars set. This is - * faster than using strchr_m(). - * - * isillegal() - Given a character, check the chartest array to see - * if that character is in the illegal characters set. - * This is faster than using strchr_m(). - * - * mangled_cache - Cache header used for storing mangled -> original - * reverse maps. - * - * mc_initialized - False until the mangled_cache structure has been - * initialized via a call to reset_mangled_cache(). - * - * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the - * cache. A value of 0 indicates "infinite". - * - * MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the - * cache. When the cache was kept as an array of 256 - * byte strings, the default cache size was 50 entries. - * This required a fixed 12.5Kbytes of memory. The - * mangled stack parameter is no longer used (though - * this might change). We're now using a fixed 16Kbyte - * maximum cache size. This will probably be much more - * than 50 entries. - */ - -char magic_char = '~'; - -static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%"; -#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1) - -static unsigned char chartest[256] = { 0 }; -static BOOL ct_initialized = False; - -#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE])) -#define BASECHAR_MASK 0xf0 -#define ILLEGAL_MASK 0x0f -#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK ) -#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK ) - -static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } }; -static BOOL mc_initialized = False; -#define MANGLED_CACHE_MAX_ENTRIES 1024 -#define MANGLED_CACHE_MAX_MEMORY 0 - -/* -------------------------------------------------------------------------- ** - * External Variables... - */ - -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. */ - -/* -------------------------------------------------------------------- */ - -static NTSTATUS has_valid_83_chars(const smb_ucs2_t *s, BOOL allow_wildcards) -{ - if (!s || !*s) - return NT_STATUS_INVALID_PARAMETER; - - /* CHECK: this should not be necessary if the ms wild chars - are not valid in valid.dat --- simo */ - if (!allow_wildcards && ms_has_wild_w(s)) - return NT_STATUS_UNSUCCESSFUL; - - while (*s) { - if(!isvalid83_w(*s)) - return NT_STATUS_UNSUCCESSFUL; - s++; - } - - return NT_STATUS_OK; -} - -/* return False if something fail and - * return 2 alloced unicode strings that contain prefix and extension - */ - -static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, - smb_ucs2_t **extension, BOOL allow_wildcards) -{ - size_t ext_len; - smb_ucs2_t *p; - - *extension = 0; - *prefix = strdup_w(ucs2_string); - if (!*prefix) { - return NT_STATUS_NO_MEMORY; - } - if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) { - ext_len = strlen_w(p+1); - if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) && - (NT_STATUS_IS_OK(has_valid_83_chars(p+1,allow_wildcards)))) /* check extension */ { - *p = 0; - *extension = strdup_w(p+1); - if (!*extension) { - SAFE_FREE(*prefix); - return NT_STATUS_NO_MEMORY; - } - } - } - return NT_STATUS_OK; -} - -/* ************************************************************************** ** - * Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name. - * - * Input: fname - String containing the name to be tested. - * - * Output: NT_STATUS_UNSUCCESSFUL, if the name matches one of the list of reserved names. - * - * Notes: This is a static function called by is_8_3(), below. - * - * ************************************************************************** ** - */ - -static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards, BOOL only_8_3) -{ - smb_ucs2_t *str, *p; - NTSTATUS ret = NT_STATUS_OK; - - if (!fname || !*fname) - return NT_STATUS_INVALID_PARAMETER; - - /* . and .. are valid names. */ - if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0) - return NT_STATUS_OK; - - /* Name cannot start with '.' */ - if (*fname == UCS2_CHAR('.')) - return NT_STATUS_UNSUCCESSFUL; - - if (only_8_3) { - ret = has_valid_83_chars(fname, allow_wildcards); - if (!NT_STATUS_IS_OK(ret)) - return ret; - } - - str = strdup_w(fname); - p = strchr_w(str, UCS2_CHAR('.')); - if (p && p[1] == UCS2_CHAR(0)) { - /* Name cannot end in '.' */ - SAFE_FREE(str); - return NT_STATUS_UNSUCCESSFUL; - } - if (p) - *p = 0; - strupper_w(str); - p = &(str[1]); - - switch(str[0]) - { - case UCS2_CHAR('A'): - if(strcmp_wa(p, "UX") == 0) - ret = NT_STATUS_UNSUCCESSFUL; - break; - case UCS2_CHAR('C'): - if((strcmp_wa(p, "LOCK$") == 0) - || (strcmp_wa(p, "ON") == 0) - || (strcmp_wa(p, "OM1") == 0) - || (strcmp_wa(p, "OM2") == 0) - || (strcmp_wa(p, "OM3") == 0) - || (strcmp_wa(p, "OM4") == 0) - ) - ret = NT_STATUS_UNSUCCESSFUL; - break; - case UCS2_CHAR('L'): - if((strcmp_wa(p, "PT1") == 0) - || (strcmp_wa(p, "PT2") == 0) - || (strcmp_wa(p, "PT3") == 0) - ) - ret = NT_STATUS_UNSUCCESSFUL; - break; - case UCS2_CHAR('N'): - if(strcmp_wa(p, "UL") == 0) - ret = NT_STATUS_UNSUCCESSFUL; - break; - case UCS2_CHAR('P'): - if(strcmp_wa(p, "RN") == 0) - ret = NT_STATUS_UNSUCCESSFUL; - break; - default: - break; - } - - SAFE_FREE(str); - return ret; -} - -static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards) -{ - smb_ucs2_t *pref = 0, *ext = 0; - size_t plen; - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - - if (!fname || !*fname) - return NT_STATUS_INVALID_PARAMETER; - - if (strlen_w(fname) > 12) - return NT_STATUS_UNSUCCESSFUL; - - if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0) - return NT_STATUS_OK; - - if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True))) - goto done; - - if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards))) - goto done; - plen = strlen_w(pref); - - if (strchr_wa(pref, '.')) - goto done; - if (plen < 1 || plen > 8) - goto done; - if (ext && (strlen_w(ext) > 3)) - goto done; - - ret = NT_STATUS_OK; - -done: - SAFE_FREE(pref); - SAFE_FREE(ext); - return ret; -} - -static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards) -{ - const char *f; - smb_ucs2_t *ucs2name; - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - size_t size; - - if (!fname || !*fname) - return False; - if ((f = strrchr(fname, '/')) == NULL) - f = fname; - else - f++; - - if (strlen(f) > 12) - return False; - - size = push_ucs2_allocate(&ucs2name, f); - if (size == (size_t)-1) { - DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n")); - goto done; - } - - ret = is_8_3_w(ucs2name, allow_wildcards); - -done: - SAFE_FREE(ucs2name); - - if (!NT_STATUS_IS_OK(ret)) { - return False; - } - - return True; -} - - - -/* -------------------------------------------------------------------------- ** - * Functions... - */ - -/* ************************************************************************** ** - * Initialize the static character test array. - * - * Input: none - * - * Output: none - * - * Notes: This function changes (loads) the contents of the <chartest> - * array. The scope of <chartest> is this file. - * - * ************************************************************************** ** - */ -static void init_chartest( void ) -{ - const char *illegalchars = "*\\/?<>|\":"; - const unsigned char *s; - - memset( (char *)chartest, '\0', 256 ); - - for( s = (const unsigned char *)illegalchars; *s; s++ ) - chartest[*s] = ILLEGAL_MASK; - - for( s = (const unsigned char *)basechars; *s; s++ ) - chartest[*s] |= BASECHAR_MASK; - - ct_initialized = True; -} - -/* ************************************************************************** ** - * Return True if the name *could be* a mangled name. - * - * Input: s - A path name - in UNIX pathname format. - * - * Output: True if the name matches the pattern described below in the - * notes, else False. - * - * Notes: The input name is *not* tested for 8.3 compliance. This must be - * done separately. This function returns true if the name contains - * a magic character followed by excactly two characters from the - * basechars list (above), which in turn are followed either by the - * nul (end of string) byte or a dot (extension) or by a '/' (end of - * a directory name). - * - * ************************************************************************** ** - */ -static BOOL is_mangled(const char *s) -{ - char *magic; - - if( !ct_initialized ) - init_chartest(); - - magic = strchr_m( s, magic_char ); - while( magic && magic[1] && magic[2] ) { /* 3 chars, 1st is magic. */ - if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */ - && isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */ - && isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */ - return( True ); /* If all above, then true, */ - magic = strchr_m( magic+1, magic_char ); /* else seek next magic. */ - } - return( False ); -} - -/* ************************************************************************** ** - * Compare two cache keys and return a value indicating their ordinal - * relationship. - * - * Input: ItemPtr - Pointer to a comparison key. In this case, this will - * be a mangled name string. - * NodePtr - Pointer to a node in the cache. The node structure - * will be followed in memory by a mangled name string. - * - * Output: A signed integer, as follows: - * (x < 0) <==> Key1 less than Key2 - * (x == 0) <==> Key1 equals Key2 - * (x > 0) <==> Key1 greater than Key2 - * - * Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for - * more info. - * - * ************************************************************************** ** - */ -static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr ) -{ - char *Key1 = (char *)ItemPtr; - char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1); - - return( StrCaseCmp( Key1, Key2 ) ); -} - -/* ************************************************************************** ** - * Free a cache entry. - * - * Input: WarrenZevon - Pointer to the entry that is to be returned to - * Nirvana. - * Output: none. - * - * Notes: This function gets around the possibility that the standard - * free() function may be implemented as a macro, or other evil - * subversions (oh, so much fun). - * - * ************************************************************************** ** - */ -static void cache_free_entry( ubi_trNodePtr WarrenZevon ) -{ - ZERO_STRUCTP(WarrenZevon); - SAFE_FREE( WarrenZevon ); -} - -/* ************************************************************************** ** - * Initializes or clears the mangled cache. - * - * Input: none. - * Output: none. - * - * Notes: There is a section below that is commented out. It shows how - * one might use lp_ calls to set the maximum memory and entry size - * of the cache. You might also want to remove the constants used - * in ubi_cacheInit() and replace them with lp_ calls. If so, then - * the calls to ubi_cacheSetMax*() would be moved into the else - * clause. Another option would be to pass in the max_entries and - * max_memory values as parameters. crh 09-Apr-1998. - * - * ************************************************************************** ** - */ - -static void mangle_reset( void ) -{ - if( !mc_initialized ) { - (void)ubi_cacheInit( mangled_cache, - cache_compare, - cache_free_entry, - MANGLED_CACHE_MAX_ENTRIES, - MANGLED_CACHE_MAX_MEMORY ); - mc_initialized = True; - } else { - (void)ubi_cacheClear( mangled_cache ); - } - - /* - (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() ); - (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() ); - */ -} - -/* ************************************************************************** ** - * Add a mangled name into the cache. - * - * Notes: If the mangled cache has not been initialized, then the - * function will simply fail. It could initialize the cache, - * but that's not the way it was done before I changed the - * cache mechanism, so I'm sticking with the old method. - * - * If the extension of the raw name maps directly to the - * extension of the mangled name, then we'll store both names - * *without* extensions. That way, we can provide consistent - * reverse mangling for all names that match. The test here is - * a bit more careful than the one done in earlier versions of - * mangle.c: - * - * - the extension must exist on the raw name, - * - it must be all lower case - * - it must match the mangled extension (to prove that no - * mangling occurred). - * - * crh 07-Apr-1998 - * - * ************************************************************************** ** - */ -static void cache_mangled_name( char *mangled_name, char *raw_name ) -{ - ubi_cacheEntryPtr new_entry; - char *s1; - char *s2; - size_t mangled_len; - size_t raw_len; - size_t i; - - /* If the cache isn't initialized, give up. */ - if( !mc_initialized ) - return; - - /* Init the string lengths. */ - mangled_len = strlen( mangled_name ); - raw_len = strlen( raw_name ); - - /* See if the extensions are unmangled. If so, store the entry - * without the extension, thus creating a "group" reverse map. - */ - s1 = strrchr( mangled_name, '.' ); - if( s1 && (s2 = strrchr( raw_name, '.' )) ) { - i = 1; - while( s1[i] && (tolower( s1[i] ) == s2[i]) ) - i++; - if( !s1[i] && !s2[i] ) { - mangled_len -= i; - raw_len -= i; - } - } - - /* Allocate a new cache entry. If the allocation fails, just return. */ - i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2; - new_entry = malloc( i ); - if( !new_entry ) - return; - - /* Fill the new cache entry, and add it to the cache. */ - s1 = (char *)(new_entry + 1); - s2 = (char *)&(s1[mangled_len + 1]); - safe_strcpy( s1, mangled_name, mangled_len ); - safe_strcpy( s2, raw_name, raw_len ); - ubi_cachePut( mangled_cache, i, new_entry, s1 ); -} - -/* ************************************************************************** ** - * Check for a name on the mangled name stack - * - * Input: s - Input *and* output string buffer. - * - * Output: True if the name was found in the cache, else False. - * - * Notes: If a reverse map is found, the function will overwrite the string - * space indicated by the input pointer <s>. This is frightening. - * It should be rewritten to return NULL if the long name was not - * found, and a pointer to the long name if it was found. - * - * ************************************************************************** ** - */ - -static BOOL check_cache( char *s ) -{ - ubi_cacheEntryPtr FoundPtr; - char *ext_start = NULL; - char *found_name; - char *saved_ext = NULL; - - /* If the cache isn't initialized, give up. */ - if( !mc_initialized ) - return( False ); - - FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); - - /* If we didn't find the name *with* the extension, try without. */ - if( !FoundPtr ) { - ext_start = strrchr( s, '.' ); - if( ext_start ) { - if((saved_ext = strdup(ext_start)) == NULL) - return False; - - *ext_start = '\0'; - FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); - /* - * At this point s is the name without the - * extension. We re-add the extension if saved_ext - * is not null, before freeing saved_ext. - */ - } - } - - /* Okay, if we haven't found it we're done. */ - if( !FoundPtr ) { - if(saved_ext) { - /* Replace the saved_ext as it was truncated. */ - (void)pstrcat( s, saved_ext ); - SAFE_FREE(saved_ext); - } - return( False ); - } - - /* If we *did* find it, we need to copy it into the string buffer. */ - found_name = (char *)(FoundPtr + 1); - found_name += (strlen( found_name ) + 1); - - (void)pstrcpy( s, found_name ); - if( saved_ext ) { - /* Replace the saved_ext as it was truncated. */ - (void)pstrcat( s, saved_ext ); - SAFE_FREE(saved_ext); - } - - return( True ); -} - -/***************************************************************************** - * do the actual mangling to 8.3 format - * the buffer must be able to hold 13 characters (including the null) - ***************************************************************************** - */ -static void to_8_3(char *s) -{ - int csum; - char *p; - char extension[4]; - char base[9]; - int baselen = 0; - int extlen = 0; - - extension[0] = 0; - base[0] = 0; - - p = strrchr(s,'.'); - if( p && (strlen(p+1) < (size_t)4) ) { - BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */ - - if( all_normal && p[1] != 0 ) { - *p = 0; - csum = str_checksum( s ); - *p = '.'; - } else - csum = str_checksum(s); - } else - csum = str_checksum(s); - - strupper_m( s ); - - if( p ) { - if( p == s ) - safe_strcpy( extension, "___", 3 ); - else { - *p++ = 0; - while( *p && extlen < 3 ) { - if ( *p != '.') { - extension[extlen++] = p[0]; - } - p++; - } - extension[extlen] = 0; - } - } - - p = s; - - while( *p && baselen < 5 ) { - if (*p != '.') { - base[baselen++] = p[0]; - } - p++; - } - base[baselen] = 0; - - csum = csum % (MANGLE_BASE*MANGLE_BASE); - - (void)slprintf(s, 12, "%s%c%c%c", - base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) ); - - if( *extension ) { - (void)pstrcat( s, "." ); - (void)pstrcat( s, extension ); - } -} - -/***************************************************************************** - * Convert a filename to DOS format. Return True if successful. - * - * Input: OutName - Source *and* destination buffer. - * - * NOTE that OutName must point to a memory space that - * is at least 13 bytes in size! - * - * need83 - If False, name mangling will be skipped unless the - * name contains illegal characters. Mapping will still - * be done, if appropriate. This is probably used to - * signal that a client does not require name mangling, - * thus skipping the name mangling even on shares which - * have name-mangling turned on. - * cache83 - If False, the mangled name cache will not be updated. - * This is usually used to prevent that we overwrite - * a conflicting cache entry prematurely, i.e. before - * we know whether the client is really interested in the - * current name. (See PR#13758). UKD. - * - * Output: Returns False only if the name wanted mangling but the share does - * not have name mangling turned on. - * - * **************************************************************************** - */ - -static void name_map(char *OutName, BOOL need83, BOOL cache83) -{ - smb_ucs2_t *OutName_ucs2; - DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName, - need83 ? "True" : "False", cache83 ? "True" : "False")); - - if (push_ucs2_allocate(&OutName_ucs2, OutName) == (size_t)-1) { - DEBUG(0, ("push_ucs2_allocate failed!\n")); - return; - } - - if( !need83 && !NT_STATUS_IS_OK(is_valid_name(OutName_ucs2, False, False))) - need83 = True; - - /* check if it's already in 8.3 format */ - if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2, False))) { - char *tmp = NULL; - - /* mangle it into 8.3 */ - if (cache83) - tmp = strdup(OutName); - - to_8_3(OutName); - - if(tmp != NULL) { - cache_mangled_name(OutName, tmp); - SAFE_FREE(tmp); - } - } - - DEBUG(5,("name_map() ==> [%s]\n", OutName)); - SAFE_FREE(OutName_ucs2); -} - -/* - the following provides the abstraction layer to make it easier - to drop in an alternative mangling implementation -*/ -static struct mangle_fns mangle_fns = { - is_mangled, - is_8_3, - mangle_reset, - check_cache, - name_map -}; - -/* return the methods for this mangling implementation */ -struct mangle_fns *mangle_hash_init(void) -{ - mangle_reset(); - - return &mangle_fns; -} diff --git a/source/smbd/mangle_hash2.c b/source/smbd/mangle_hash2.c deleted file mode 100644 index 62087e7e593..00000000000 --- a/source/smbd/mangle_hash2.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - Unix SMB/CIFS implementation. - new hash based name mangling implementation - Copyright (C) Andrew Tridgell 2002 - Copyright (C) Simo Sorce 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - this mangling scheme uses the following format - - Annnn~n.AAA - - where nnnnn is a base 36 hash, and A represents characters from the original string - - The hash is taken of the leading part of the long filename, in uppercase - - for simplicity, we only allow ascii characters in 8.3 names - */ - - /* hash alghorithm changed to FNV1 by idra@samba.org (Simo Sorce). - * see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a - * discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors - */ - -/* - =============================================================================== - NOTE NOTE NOTE!!! - - This file deliberately uses non-multibyte string functions in many places. This - is *not* a mistake. This code is multi-byte safe, but it gets this property - through some very subtle knowledge of the way multi-byte strings are encoded - and the fact that this mangling algorithm only supports ascii characters in - 8.3 names. - - please don't convert this file to use the *_m() functions!! - =============================================================================== -*/ - - -#include "includes.h" - -#if 1 -#define M_DEBUG(level, x) DEBUG(level, x) -#else -#define M_DEBUG(level, x) -#endif - -/* these flags are used to mark characters in as having particular - properties */ -#define FLAG_BASECHAR 1 -#define FLAG_ASCII 2 -#define FLAG_ILLEGAL 4 -#define FLAG_WILDCARD 8 - -/* the "possible" flags are used as a fast way to find possible DOS - reserved filenames */ -#define FLAG_POSSIBLE1 16 -#define FLAG_POSSIBLE2 32 -#define FLAG_POSSIBLE3 64 -#define FLAG_POSSIBLE4 128 - -/* by default have a max of 4096 entries in the cache. */ -#ifndef MANGLE_CACHE_SIZE -#define MANGLE_CACHE_SIZE 4096 -#endif - -#define FNV1_PRIME 0x01000193 -/*the following number is a fnv1 of the string: idra@samba.org 2002 */ -#define FNV1_INIT 0xa6b93095 - -/* these tables are used to provide fast tests for characters */ -static unsigned char char_flags[256]; - -#define FLAG_CHECK(c, flag) (char_flags[(unsigned char)(c)] & (flag)) - -/* - this determines how many characters are used from the original filename - in the 8.3 mangled name. A larger value leads to a weaker hash and more collisions. - The largest possible value is 6. -*/ -static unsigned mangle_prefix; - -/* we will use a very simple direct mapped prefix cache. The big - advantage of this cache structure is speed and low memory usage - - The cache is indexed by the low-order bits of the hash, and confirmed by - hashing the resulting cache entry to match the known hash -*/ -static char **prefix_cache; -static u32 *prefix_cache_hashes; - -/* these are the characters we use in the 8.3 hash. Must be 36 chars long */ -static const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -static unsigned char base_reverse[256]; -#define base_forward(v) basechars[v] - -/* the list of reserved dos names - all of these are illegal */ -static const char *reserved_names[] = -{ "AUX", "LOCK$", "CON", "COM1", "COM2", "COM3", "COM4", - "LPT1", "LPT2", "LPT3", "NUL", "PRN", NULL }; - -/* - hash a string of the specified length. The string does not need to be - null terminated - - this hash needs to be fast with a low collision rate (what hash doesn't?) -*/ -static u32 mangle_hash(const char *key, unsigned length) -{ - u32 value; - u32 i; - fstring str; - - /* we have to uppercase here to ensure that the mangled name - doesn't depend on the case of the long name. Note that this - is the only place where we need to use a multi-byte string - function */ - strncpy(str, key, length); - str[length] = 0; - strupper_m(str); - - /* the length of a multi-byte string can change after a strupper_m */ - length = strlen(str); - - /* Set the initial value from the key size. */ - for (value = FNV1_INIT, i=0; i < length; i++) { - value *= (u32)FNV1_PRIME; - value ^= (u32)(str[i]); - } - - /* note that we force it to a 31 bit hash, to keep within the limits - of the 36^6 mangle space */ - return value & ~0x80000000; -} - -/* - initialise (ie. allocate) the prefix cache - */ -static BOOL cache_init(void) -{ - if (prefix_cache) return True; - - prefix_cache = calloc(MANGLE_CACHE_SIZE, sizeof(char *)); - if (!prefix_cache) return False; - - prefix_cache_hashes = calloc(MANGLE_CACHE_SIZE, sizeof(u32)); - if (!prefix_cache_hashes) return False; - - return True; -} - -/* - insert an entry into the prefix cache. The string might not be null - terminated */ -static void cache_insert(const char *prefix, int length, u32 hash) -{ - int i = hash % MANGLE_CACHE_SIZE; - - if (prefix_cache[i]) { - free(prefix_cache[i]); - } - - prefix_cache[i] = strndup(prefix, length); - prefix_cache_hashes[i] = hash; -} - -/* - lookup an entry in the prefix cache. Return NULL if not found. -*/ -static const char *cache_lookup(u32 hash) -{ - int i = hash % MANGLE_CACHE_SIZE; - - if (!prefix_cache[i] || hash != prefix_cache_hashes[i]) { - return NULL; - } - - /* yep, it matched */ - return prefix_cache[i]; -} - - -/* - determine if a string is possibly in a mangled format, ignoring - case - - In this algorithm, mangled names use only pure ascii characters (no - multi-byte) so we can avoid doing a UCS2 conversion - */ -static BOOL is_mangled_component(const char *name, size_t len) -{ - unsigned int i; - - M_DEBUG(10,("is_mangled_component %s (len %u) ?\n", name, (unsigned int)len)); - - /* check the length */ - if (len > 12 || len < 8) - return False; - - /* the best distinguishing characteristic is the ~ */ - if (name[6] != '~') - return False; - - /* check extension */ - if (len > 8) { - if (name[8] != '.') - return False; - for (i=9; name[i] && i < len; i++) { - if (! FLAG_CHECK(name[i], FLAG_ASCII)) { - return False; - } - } - } - - /* check lead characters */ - for (i=0;i<mangle_prefix;i++) { - if (! FLAG_CHECK(name[i], FLAG_ASCII)) { - return False; - } - } - - /* check rest of hash */ - if (! FLAG_CHECK(name[7], FLAG_BASECHAR)) { - return False; - } - for (i=mangle_prefix;i<6;i++) { - if (! FLAG_CHECK(name[i], FLAG_BASECHAR)) { - return False; - } - } - - M_DEBUG(10,("is_mangled_component %s (len %u) -> yes\n", name, (unsigned int)len)); - - return True; -} - - - -/* - determine if a string is possibly in a mangled format, ignoring - case - - In this algorithm, mangled names use only pure ascii characters (no - multi-byte) so we can avoid doing a UCS2 conversion - - NOTE! This interface must be able to handle a path with unix - directory separators. It should return true if any component is - mangled - */ -static BOOL is_mangled(const char *name) -{ - const char *p; - const char *s; - - M_DEBUG(10,("is_mangled %s ?\n", name)); - - for (s=name; (p=strchr(s, '/')); s=p+1) { - if (is_mangled_component(s, PTR_DIFF(p, s))) { - return True; - } - } - - /* and the last part ... */ - return is_mangled_component(s,strlen(s)); -} - - -/* - see if a filename is an allowable 8.3 name. - - we are only going to allow ascii characters in 8.3 names, as this - simplifies things greatly (it means that we know the string won't - get larger when converted from UNIX to DOS formats) -*/ -static BOOL is_8_3(const char *name, BOOL check_case, BOOL allow_wildcards) -{ - int len, i; - char *dot_p; - - /* as a special case, the names '.' and '..' are allowable 8.3 names */ - if (name[0] == '.') { - if (!name[1] || (name[1] == '.' && !name[2])) { - return True; - } - } - - /* the simplest test is on the overall length of the - filename. Note that we deliberately use the ascii string - length (not the multi-byte one) as it is faster, and gives us - the result we need in this case. Using strlen_m would not - only be slower, it would be incorrect */ - len = strlen(name); - if (len > 12) - return False; - - /* find the '.'. Note that once again we use the non-multibyte - function */ - dot_p = strchr(name, '.'); - - if (!dot_p) { - /* if the name doesn't contain a '.' then its length - must be less than 8 */ - if (len > 8) { - return False; - } - } else { - int prefix_len, suffix_len; - - /* if it does contain a dot then the prefix must be <= - 8 and the suffix <= 3 in length */ - prefix_len = PTR_DIFF(dot_p, name); - suffix_len = len - (prefix_len+1); - - if (prefix_len > 8 || suffix_len > 3 || suffix_len == 0) { - return False; - } - - /* a 8.3 name cannot contain more than 1 '.' */ - if (strchr(dot_p+1, '.')) { - return False; - } - } - - /* the length are all OK. Now check to see if the characters themselves are OK */ - for (i=0; name[i]; i++) { - /* note that we may allow wildcard petterns! */ - if (!FLAG_CHECK(name[i], FLAG_ASCII|(allow_wildcards ? FLAG_WILDCARD : 0)) && name[i] != '.') { - return False; - } - } - - /* it is a good 8.3 name */ - return True; -} - - -/* - reset the mangling cache on a smb.conf reload. This only really makes sense for - mangling backends that have parameters in smb.conf, and as this backend doesn't - this is a NULL operation -*/ -static void mangle_reset(void) -{ - /* noop */ -} - - -/* - try to find a 8.3 name in the cache, and if found then - replace the string with the original long name. - - The filename must be able to hold at least sizeof(fstring) -*/ -static BOOL check_cache(char *name) -{ - u32 hash, multiplier; - unsigned int i; - const char *prefix; - char extension[4]; - - /* make sure that this is a mangled name from this cache */ - if (!is_mangled(name)) { - M_DEBUG(10,("check_cache: %s -> not mangled\n", name)); - return False; - } - - /* we need to extract the hash from the 8.3 name */ - hash = base_reverse[(unsigned char)name[7]]; - for (multiplier=36, i=5;i>=mangle_prefix;i--) { - u32 v = base_reverse[(unsigned char)name[i]]; - hash += multiplier * v; - multiplier *= 36; - } - - /* now look in the prefix cache for that hash */ - prefix = cache_lookup(hash); - if (!prefix) { - M_DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash)); - return False; - } - - /* we found it - construct the full name */ - if (name[8] == '.') { - strncpy(extension, name+9, 3); - extension[3] = 0; - } else { - extension[0] = 0; - } - - if (extension[0]) { - M_DEBUG(10,("check_cache: %s -> %s.%s\n", name, prefix, extension)); - slprintf(name, sizeof(fstring), "%s.%s", prefix, extension); - } else { - M_DEBUG(10,("check_cache: %s -> %s\n", name, prefix)); - fstrcpy(name, prefix); - } - - return True; -} - - -/* - look for a DOS reserved name -*/ -static BOOL is_reserved_name(const char *name) -{ - if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) && - FLAG_CHECK(name[1], FLAG_POSSIBLE2) && - FLAG_CHECK(name[2], FLAG_POSSIBLE3) && - FLAG_CHECK(name[3], FLAG_POSSIBLE4)) { - /* a likely match, scan the lot */ - int i; - for (i=0; reserved_names[i]; i++) { - int len = strlen(reserved_names[i]); - /* note that we match on COM1 as well as COM1.foo */ - if (strnequal(name, reserved_names[i], len) && - (name[len] == '.' || name[len] == 0)) { - return True; - } - } - } - - return False; -} - -/* - See if a filename is a legal long filename. - A filename ending in a '.' is not legal unless it's "." or "..". JRA. -*/ - -static BOOL is_legal_name(const char *name) -{ - const char *dot_pos = NULL; - BOOL alldots = True; - size_t numdots = 0; - - while (*name) { - if (((unsigned int)name[0]) > 128 && (name[1] != 0)) { - /* Possible start of mb character. */ - char mbc[2]; - /* - * Note that if CH_UNIX is utf8 a string may be 3 - * bytes, but this is ok as mb utf8 characters don't - * contain embedded ascii bytes. We are really checking - * for mb UNIX asian characters like Japanese (SJIS) here. - * JRA. - */ - if (convert_string(CH_UNIX, CH_UCS2, name, 2, mbc, 2, False) == 2) { - /* Was a good mb string. */ - name += 2; - continue; - } - } - - if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) { - return False; - } - if (name[0] == '.') { - dot_pos = name; - numdots++; - } else { - alldots = False; - } - name++; - } - - if (dot_pos) { - if (alldots && (numdots == 1 || numdots == 2)) - return True; /* . or .. is a valid name */ - - /* A valid long name cannot end in '.' */ - if (dot_pos[1] == '\0') - return False; - } - - return True; -} - -/* - the main forward mapping function, which converts a long filename to - a 8.3 name - - if need83 is not set then we only do the mangling if the name is illegal - as a long name - - if cache83 is not set then we don't cache the result - - the name parameter must be able to hold 13 bytes -*/ -static void name_map(fstring name, BOOL need83, BOOL cache83) -{ - char *dot_p; - char lead_chars[7]; - char extension[4]; - unsigned int extension_length, i; - unsigned int prefix_len; - u32 hash, v; - char new_name[13]; - - /* reserved names are handled specially */ - if (!is_reserved_name(name)) { - /* if the name is already a valid 8.3 name then we don't need to - do anything */ - if (is_8_3(name, False, False)) { - return; - } - - /* if the caller doesn't strictly need 8.3 then just check for illegal - filenames */ - if (!need83 && is_legal_name(name)) { - return; - } - } - - /* find the '.' if any */ - dot_p = strrchr(name, '.'); - - if (dot_p) { - /* if the extension contains any illegal characters or - is too long or zero length then we treat it as part - of the prefix */ - for (i=0; i<4 && dot_p[i+1]; i++) { - if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) { - dot_p = NULL; - break; - } - } - if (i == 0 || i == 4) dot_p = NULL; - } - - /* the leading characters in the mangled name is taken from - the first characters of the name, if they are ascii otherwise - '_' is used - */ - for (i=0;i<mangle_prefix && name[i];i++) { - lead_chars[i] = name[i]; - if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) { - lead_chars[i] = '_'; - } - lead_chars[i] = toupper(lead_chars[i]); - } - for (;i<mangle_prefix;i++) { - lead_chars[i] = '_'; - } - - /* the prefix is anything up to the first dot */ - if (dot_p) { - prefix_len = PTR_DIFF(dot_p, name); - } else { - prefix_len = strlen(name); - } - - /* the extension of the mangled name is taken from the first 3 - ascii chars after the dot */ - extension_length = 0; - if (dot_p) { - for (i=1; extension_length < 3 && dot_p[i]; i++) { - char c = dot_p[i]; - if (FLAG_CHECK(c, FLAG_ASCII)) { - extension[extension_length++] = toupper(c); - } - } - } - - /* find the hash for this prefix */ - v = hash = mangle_hash(name, prefix_len); - - /* now form the mangled name. */ - for (i=0;i<mangle_prefix;i++) { - new_name[i] = lead_chars[i]; - } - new_name[7] = base_forward(v % 36); - new_name[6] = '~'; - for (i=5; i>=mangle_prefix; i--) { - v = v / 36; - new_name[i] = base_forward(v % 36); - } - - /* add the extension */ - if (extension_length) { - new_name[8] = '.'; - memcpy(&new_name[9], extension, extension_length); - new_name[9+extension_length] = 0; - } else { - new_name[8] = 0; - } - - if (cache83) { - /* put it in the cache */ - cache_insert(name, prefix_len, hash); - } - - M_DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n", - name, hash, new_name, cache83)); - - /* and overwrite the old name */ - fstrcpy(name, new_name); - - /* all done, we've managed to mangle it */ -} - - -/* initialise the flags table - - we allow only a very restricted set of characters as 'ascii' in this - mangling backend. This isn't a significant problem as modern clients - use the 'long' filenames anyway, and those don't have these - restrictions. -*/ -static void init_tables(void) -{ - int i; - - memset(char_flags, 0, sizeof(char_flags)); - - for (i=1;i<128;i++) { - if ((i >= '0' && i <= '9') || - (i >= 'a' && i <= 'z') || - (i >= 'A' && i <= 'Z')) { - char_flags[i] |= (FLAG_ASCII | FLAG_BASECHAR); - } - if (strchr("_-$~", i)) { - char_flags[i] |= FLAG_ASCII; - } - - if (strchr("*\\/?<>|\":", i)) { - char_flags[i] |= FLAG_ILLEGAL; - } - - if (strchr("*?\"<>", i)) { - char_flags[i] |= FLAG_WILDCARD; - } - } - - memset(base_reverse, 0, sizeof(base_reverse)); - for (i=0;i<36;i++) { - base_reverse[(unsigned char)base_forward(i)] = i; - } - - /* fill in the reserved names flags. These are used as a very - fast filter for finding possible DOS reserved filenames */ - for (i=0; reserved_names[i]; i++) { - unsigned char c1, c2, c3, c4; - - c1 = (unsigned char)reserved_names[i][0]; - c2 = (unsigned char)reserved_names[i][1]; - c3 = (unsigned char)reserved_names[i][2]; - c4 = (unsigned char)reserved_names[i][3]; - - char_flags[c1] |= FLAG_POSSIBLE1; - char_flags[c2] |= FLAG_POSSIBLE2; - char_flags[c3] |= FLAG_POSSIBLE3; - char_flags[c4] |= FLAG_POSSIBLE4; - char_flags[tolower(c1)] |= FLAG_POSSIBLE1; - char_flags[tolower(c2)] |= FLAG_POSSIBLE2; - char_flags[tolower(c3)] |= FLAG_POSSIBLE3; - char_flags[tolower(c4)] |= FLAG_POSSIBLE4; - - char_flags[(unsigned char)'.'] |= FLAG_POSSIBLE4; - } -} - - -/* - the following provides the abstraction layer to make it easier - to drop in an alternative mangling implementation */ -static struct mangle_fns mangle_fns = { - is_mangled, - is_8_3, - mangle_reset, - check_cache, - name_map -}; - -/* return the methods for this mangling implementation */ -struct mangle_fns *mangle_hash2_init(void) -{ - /* the mangle prefix can only be in the mange 1 to 6 */ - mangle_prefix = lp_mangle_prefix(); - if (mangle_prefix > 6) { - mangle_prefix = 6; - } - if (mangle_prefix < 1) { - mangle_prefix = 1; - } - - init_tables(); - mangle_reset(); - - if (!cache_init()) { - return NULL; - } - - return &mangle_fns; -} diff --git a/source/smbd/mangle_map.c b/source/smbd/mangle_map.c deleted file mode 100644 index 9e798fd41b4..00000000000 --- a/source/smbd/mangle_map.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Name mapping code - Copyright (C) Jeremy Allison 1998 - Copyright (C) Andrew Tridgell 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - -/* ************************************************************************** ** - * Used only in do_fwd_mangled_map(), below. - * ************************************************************************** ** - */ -static char *map_filename( char *s, /* This is null terminated */ - const char *pattern, /* This isn't. */ - int len ) /* This is the length of pattern. */ - { - static pstring matching_bit; /* The bit of the string which matches */ - /* a * in pattern if indeed there is a * */ - char *sp; /* Pointer into s. */ - char *pp; /* Pointer into p. */ - char *match_start; /* Where the matching bit starts. */ - pstring pat; - - StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */ - pstrcpy( matching_bit, "" ); /* Match but no star gets this. */ - pp = pat; /* Initialize the pointers. */ - sp = s; - - if( strequal(s, ".") || strequal(s, "..")) - { - return NULL; /* Do not map '.' and '..' */ - } - - if( (len == 1) && (*pattern == '*') ) - { - return NULL; /* Impossible, too ambiguous for */ - } /* words! */ - - while( (*sp) /* Not the end of the string. */ - && (*pp) /* Not the end of the pattern. */ - && (*sp == *pp) /* The two match. */ - && (*pp != '*') ) /* No wildcard. */ - { - sp++; /* Keep looking. */ - pp++; - } - - if( !*sp && !*pp ) /* End of pattern. */ - return( matching_bit ); /* Simple match. Return empty string. */ - - if( *pp == '*' ) - { - pp++; /* Always interrested in the chacter */ - /* after the '*' */ - if( !*pp ) /* It is at the end of the pattern. */ - { - StrnCpy( matching_bit, s, sp-s ); - return( matching_bit ); - } - else - { - /* The next character in pattern must match a character further */ - /* along s than sp so look for that character. */ - match_start = sp; - while( (*sp) /* Not the end of s. */ - && (*sp != *pp) ) /* Not the same */ - sp++; /* Keep looking. */ - if( !*sp ) /* Got to the end without a match. */ - { - return( NULL ); - } /* Still hope for a match. */ - else - { - /* Now sp should point to a matching character. */ - StrnCpy(matching_bit, match_start, sp-match_start); - /* Back to needing a stright match again. */ - while( (*sp) /* Not the end of the string. */ - && (*pp) /* Not the end of the pattern. */ - && (*sp == *pp) ) /* The two match. */ - { - sp++; /* Keep looking. */ - pp++; - } - if( !*sp && !*pp ) /* Both at end so it matched */ - return( matching_bit ); - else - return( NULL ); - } - } - } - return( NULL ); /* No match. */ - } /* map_filename */ - - -/* ************************************************************************** ** - * MangledMap is a series of name pairs in () separated by spaces. - * If s matches the first of the pair then the name given is the - * second of the pair. A * means any number of any character and if - * present in the second of the pair as well as the first the - * matching part of the first string takes the place of the * in the - * second. - * - * I wanted this so that we could have RCS files which can be used - * by UNIX and DOS programs. My mapping string is (RCS rcs) which - * converts the UNIX RCS file subdirectory to lowercase thus - * preventing mangling. - * - * See 'mangled map' in smb.conf(5). - * - * ************************************************************************** ** - */ -static void mangled_map(char *s, const char *MangledMap) -{ - const char *start=MangledMap; /* Use this to search for mappings. */ - const char *end; /* Used to find the end of strings. */ - char *match_string; - pstring new_string; /* Make up the result here. */ - char *np; /* Points into new_string. */ - - DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) ); - while( *start ) { - while( (*start) && (*start != '(') ) - start++; - if( !*start ) - continue; /* Always check for the end. */ - start++; /* Skip the ( */ - end = start; /* Search for the ' ' or a ')' */ - DEBUG( 5, ("Start of first in pair '%s'\n", start) ); - while( (*end) && !((*end == ' ') || (*end == ')')) ) - end++; - if( !*end ) { - start = end; - continue; /* Always check for the end. */ - } - DEBUG( 5, ("End of first in pair '%s'\n", end) ); - if( (match_string = map_filename( s, start, end-start )) ) { - int size_left = sizeof(new_string) - 1; - DEBUG( 5, ("Found a match\n") ); - /* Found a match. */ - start = end + 1; /* Point to start of what it is to become. */ - DEBUG( 5, ("Start of second in pair '%s'\n", start) ); - end = start; - np = new_string; - while( (*end && size_left > 0) /* Not the end of string. */ - && (*end != ')') /* Not the end of the pattern. */ - && (*end != '*') ) { /* Not a wildcard. */ - *np++ = *end++; - size_left--; - } - - if( !*end ) { - start = end; - continue; /* Always check for the end. */ - } - if( *end == '*' ) { - if (size_left > 0 ) - safe_strcpy( np, match_string, size_left ); - np += strlen( match_string ); - size_left -= strlen( match_string ); - end++; /* Skip the '*' */ - while ((*end && size_left > 0) /* Not the end of string. */ - && (*end != ')') /* Not the end of the pattern. */ - && (*end != '*')) { /* Not a wildcard. */ - *np++ = *end++; - size_left--; - } - } - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - if (size_left > 0) - *np++ = '\0'; /* NULL terminate it. */ - DEBUG(5,("End of second in pair '%s'\n", end)); - new_string[sizeof(new_string)-1] = '\0'; - pstrcpy( s, new_string ); /* Substitute with the new name. */ - DEBUG( 5, ("s is now '%s'\n", s) ); - } - start = end; /* Skip a bit which cannot be wanted anymore. */ - start++; - } -} - -/* - front end routine to the mangled map code - personally I think that the whole idea of "mangled map" is completely bogus -*/ -void mangle_map_filename(fstring fname, int snum) -{ - char *map; - - map = lp_mangled_map(snum); - if (!map || !*map) return; - - mangled_map(fname, map); -} diff --git a/source/smbd/message.c b/source/smbd/message.c deleted file mode 100644 index f853a914753..00000000000 --- a/source/smbd/message.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB messaging - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This file handles the messaging system calls for winpopup style - messages -*/ - - -#include "includes.h" - -extern userdom_struct current_user_info; - -/* look in server.c for some explanation of these variables */ -static char msgbuf[1600]; -static int msgpos; -static fstring msgfrom; -static fstring msgto; - -/**************************************************************************** -deliver the message -****************************************************************************/ -static void msg_deliver(void) -{ - pstring name; - int i; - int fd; - char *msg; - int len; - - if (! (*lp_msg_command())) - { - DEBUG(1,("no messaging command specified\n")); - msgpos = 0; - return; - } - - /* put it in a temporary file */ - slprintf(name,sizeof(name)-1, "%s/msg.XXXXXX",tmpdir()); - fd = smb_mkstemp(name); - - if (fd == -1) { - DEBUG(1,("can't open message file %s\n",name)); - return; - } - - /* - * Incoming message is in DOS codepage format. Convert to UNIX. - */ - - if ((len = (int)convert_string_allocate(NULL,CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg, True)) < 0 || !msg) { - DEBUG(3,("Conversion failed, delivering message in DOS codepage format\n")); - for (i = 0; i < msgpos;) { - if (msgbuf[i] == '\r' && i < (msgpos-1) && msgbuf[i+1] == '\n') { - i++; continue; - } - write(fd, &msgbuf[i++], 1); - } - } else { - for (i = 0; i < len;) { - if (msg[i] == '\r' && i < (len-1) && msg[i+1] == '\n') { - i++; continue; - } - write(fd, &msg[i++],1); - } - SAFE_FREE(msg); - } - close(fd); - - - /* run the command */ - if (*lp_msg_command()) - { - fstring alpha_msgfrom; - fstring alpha_msgto; - pstring s; - - pstrcpy(s,lp_msg_command()); - pstring_sub(s,"%f",alpha_strcpy(alpha_msgfrom,msgfrom,NULL,sizeof(alpha_msgfrom))); - pstring_sub(s,"%t",alpha_strcpy(alpha_msgto,msgto,NULL,sizeof(alpha_msgto))); - standard_sub_basic(current_user_info.smb_name, s, sizeof(s)); - pstring_sub(s,"%s",name); - smbrun(s,NULL); - } - - msgpos = 0; -} - - - -/**************************************************************************** - reply to a sends -****************************************************************************/ -int reply_sends(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int len; - char *msg; - int outsize = 0; - char *p; - - START_PROFILE(SMBsends); - - msgpos = 0; - - if (! (*lp_msg_command())) { - END_PROFILE(SMBsends); - return(ERROR_DOS(ERRSRV,ERRmsgoff)); - } - - outsize = set_message(outbuf,0,0,True); - - p = smb_buf(inbuf)+1; - p += srvstr_pull_buf(inbuf, msgfrom, p, sizeof(msgfrom), STR_TERMINATE) + 1; - p += srvstr_pull_buf(inbuf, msgto, p, sizeof(msgto), STR_TERMINATE) + 1; - - msg = p; - - len = SVAL(msg,0); - len = MIN(len,sizeof(msgbuf)-msgpos); - - memset(msgbuf,'\0',sizeof(msgbuf)); - - memcpy(&msgbuf[msgpos],msg+2,len); - msgpos += len; - - msg_deliver(); - - END_PROFILE(SMBsends); - return(outsize); -} - - -/**************************************************************************** - reply to a sendstrt -****************************************************************************/ -int reply_sendstrt(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - char *p; - - START_PROFILE(SMBsendstrt); - - if (! (*lp_msg_command())) { - END_PROFILE(SMBsendstrt); - return(ERROR_DOS(ERRSRV,ERRmsgoff)); - } - - outsize = set_message(outbuf,1,0,True); - - memset(msgbuf,'\0',sizeof(msgbuf)); - msgpos = 0; - - p = smb_buf(inbuf)+1; - p += srvstr_pull_buf(inbuf, msgfrom, p, sizeof(msgfrom), STR_TERMINATE) + 1; - p += srvstr_pull_buf(inbuf, msgto, p, sizeof(msgto), STR_TERMINATE) + 1; - - DEBUG( 3, ( "SMBsendstrt (from %s to %s)\n", msgfrom, msgto ) ); - - END_PROFILE(SMBsendstrt); - return(outsize); -} - - -/**************************************************************************** - reply to a sendtxt -****************************************************************************/ -int reply_sendtxt(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int len; - int outsize = 0; - char *msg; - START_PROFILE(SMBsendtxt); - - if (! (*lp_msg_command())) { - END_PROFILE(SMBsendtxt); - return(ERROR_DOS(ERRSRV,ERRmsgoff)); - } - - outsize = set_message(outbuf,0,0,True); - - msg = smb_buf(inbuf) + 1; - - len = SVAL(msg,0); - len = MIN(len,sizeof(msgbuf)-msgpos); - - memcpy(&msgbuf[msgpos],msg+2,len); - msgpos += len; - - DEBUG( 3, ( "SMBsendtxt\n" ) ); - - END_PROFILE(SMBsendtxt); - return(outsize); -} - - -/**************************************************************************** - reply to a sendend -****************************************************************************/ -int reply_sendend(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - START_PROFILE(SMBsendend); - - if (! (*lp_msg_command())) { - END_PROFILE(SMBsendend); - return(ERROR_DOS(ERRSRV,ERRmsgoff)); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("SMBsendend\n")); - - msg_deliver(); - - END_PROFILE(SMBsendend); - return(outsize); -} diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c deleted file mode 100644 index 96961368fb1..00000000000 --- a/source/smbd/negprot.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - Unix SMB/CIFS implementation. - negprot reply code - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern int Protocol; -extern int max_recv; -BOOL global_encrypted_passwords_negotiated = False; -BOOL global_spnego_negotiated = False; -struct auth_context *negprot_global_auth_context = NULL; - -static void get_challenge(char buff[8]) -{ - NTSTATUS nt_status; - const uint8 *cryptkey; - - /* We might be called more than once, muliple negprots are premitted */ - if (negprot_global_auth_context) { - DEBUG(3, ("get challenge: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n")); - (negprot_global_auth_context->free)(&negprot_global_auth_context); - } - - DEBUG(10, ("get challenge: creating negprot_global_auth_context\n")); - if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) { - DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status))); - smb_panic("cannot make_negprot_global_auth_context!\n"); - } - DEBUG(10, ("get challenge: getting challenge\n")); - cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context); - memcpy(buff, cryptkey, 8); -} - -/**************************************************************************** - Reply for the core protocol. -****************************************************************************/ - -static int reply_corep(char *inbuf, char *outbuf) -{ - int outsize = set_message(outbuf,1,0,True); - - Protocol = PROTOCOL_CORE; - - return outsize; -} - -/**************************************************************************** - Reply for the coreplus protocol. -****************************************************************************/ - -static int reply_coreplus(char *inbuf, char *outbuf) -{ - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int outsize = set_message(outbuf,13,0,True); - SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support - readbraw and writebraw (possibly) */ - /* Reply, SMBlockread, SMBwritelock supported. */ - SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */ - - Protocol = PROTOCOL_COREPLUS; - - return outsize; -} - -/**************************************************************************** - Reply for the lanman 1.0 protocol. -****************************************************************************/ - -static int reply_lanman1(char *inbuf, char *outbuf) -{ - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int secword=0; - time_t t = time(NULL); - - global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - - if (lp_security()>=SEC_USER) - secword |= NEGOTIATE_SECURITY_USER_LEVEL; - if (global_encrypted_passwords_negotiated) - secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - - set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); - SSVAL(outbuf,smb_vwv1,secword); - /* Create a token value and add it to the outgoing packet. */ - if (global_encrypted_passwords_negotiated) { - get_challenge(smb_buf(outbuf)); - SSVAL(outbuf,smb_vwv11, 8); - } - - Protocol = PROTOCOL_LANMAN1; - - /* Reply, SMBlockread, SMBwritelock supported. */ - SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(outbuf,smb_vwv2,max_recv); - SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */ - SSVAL(outbuf,smb_vwv4,1); - SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support - readbraw writebraw (possibly) */ - SIVAL(outbuf,smb_vwv6,sys_getpid()); - SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); - - put_dos_date(outbuf,smb_vwv8,t); - - return (smb_len(outbuf)+4); -} - -/**************************************************************************** - Reply for the lanman 2.0 protocol. -****************************************************************************/ - -static int reply_lanman2(char *inbuf, char *outbuf) -{ - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int secword=0; - time_t t = time(NULL); - - global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - - if (lp_security()>=SEC_USER) - secword |= NEGOTIATE_SECURITY_USER_LEVEL; - if (global_encrypted_passwords_negotiated) - secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - - set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); - SSVAL(outbuf,smb_vwv1,secword); - SIVAL(outbuf,smb_vwv6,sys_getpid()); - - /* Create a token value and add it to the outgoing packet. */ - if (global_encrypted_passwords_negotiated) { - get_challenge(smb_buf(outbuf)); - SSVAL(outbuf,smb_vwv11, 8); - } - - Protocol = PROTOCOL_LANMAN2; - - /* Reply, SMBlockread, SMBwritelock supported. */ - SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(outbuf,smb_vwv2,max_recv); - SSVAL(outbuf,smb_vwv3,lp_maxmux()); - SSVAL(outbuf,smb_vwv4,1); - SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */ - SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); - put_dos_date(outbuf,smb_vwv8,t); - - return (smb_len(outbuf)+4); -} - -/**************************************************************************** - Generate the spnego negprot reply blob. Return the number of bytes used. -****************************************************************************/ - -static int negprot_spnego(char *p) -{ - DATA_BLOB blob; - nstring dos_name; - fstring unix_name; - uint8 guid[17]; - const char *OIDs_krb5[] = {OID_KERBEROS5, - OID_KERBEROS5_OLD, - OID_NTLMSSP, - NULL}; - const char *OIDs_plain[] = {OID_NTLMSSP, NULL}; - char *principal; - int len; - - global_spnego_negotiated = True; - - ZERO_STRUCT(guid); - - safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1); - strlower_m(unix_name); - push_ascii_nstring(dos_name, unix_name); - safe_strcpy((char *)guid, dos_name, sizeof(guid)-1); - -#ifdef DEVELOPER - /* valgrind fixer... */ - { - size_t sl = strlen(guid); - if (sizeof(guid)-sl) - memset(&guid[sl], '\0', sizeof(guid)-sl); - } -#endif - -#if 0 - /* strangely enough, NT does not sent the single OID NTLMSSP when - not a ADS member, it sends no OIDs at all - - we can't do this until we teach our sesssion setup parser to know - about raw NTLMSSP (clients send no ASN.1 wrapping if we do this) - */ - if (lp_security() != SEC_ADS) { - memcpy(p, guid, 16); - return 16; - } -#endif - if (lp_security() != SEC_ADS) { - blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE"); - } else { - asprintf(&principal, "%s$@%s", guid, lp_realm()); - blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal); - free(principal); - } - memcpy(p, blob.data, blob.length); - len = blob.length; - data_blob_free(&blob); - return len; -} - -/**************************************************************************** - Reply for the nt protocol. -****************************************************************************/ - -static int reply_nt1(char *inbuf, 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 secword=0; - time_t t = time(NULL); - char *p, *q; - BOOL negotiate_spnego = False; - - global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - - /* do spnego in user level security if the client - supports it and we can do encrypted passwords */ - - if (global_encrypted_passwords_negotiated && - (lp_security() != SEC_SHARE) && - lp_use_spnego() && - (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { - negotiate_spnego = True; - capabilities |= CAP_EXTENDED_SECURITY; - } - - capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS; - - if (lp_unix_extensions()) { - capabilities |= CAP_UNIX; - } - - if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) - capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS; - - if (SMB_OFF_T_BITS == 64) - capabilities |= CAP_LARGE_FILES; - - if (lp_readraw() && lp_writeraw()) - capabilities |= CAP_RAW_MODE; - - /* allow for disabling unicode */ - if (lp_unicode()) - capabilities |= CAP_UNICODE; - - if (lp_nt_status_support()) - capabilities |= CAP_STATUS32; - - if (lp_host_msdfs()) - capabilities |= CAP_DFS; - - if (lp_security() >= SEC_USER) - secword |= NEGOTIATE_SECURITY_USER_LEVEL; - if (global_encrypted_passwords_negotiated) - secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - - if (lp_server_signing()) { - if (lp_security() >= SEC_USER) { - secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED; - /* No raw mode with smb signing. */ - capabilities &= ~CAP_RAW_MODE; - if (lp_server_signing() == Required) - secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; - srv_set_signing_negotiated(); - } else { - DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n")); - if (lp_server_signing() == Required) { - exit_server("reply_nt1: smb signing required and share level security selected."); - } - } - } - - set_message(outbuf,17,0,True); - - SCVAL(outbuf,smb_vwv1,secword); - - Protocol = PROTOCOL_NT1; - - SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */ - SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */ - SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */ - SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */ - SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */ - SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */ - put_long_date(outbuf+smb_vwv11+1,t); - SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60); - - p = q = smb_buf(outbuf); - if (!negotiate_spnego) { - /* Create a token value and add it to the outgoing packet. */ - if (global_encrypted_passwords_negotiated) { - /* note that we do not send a challenge at all if - we are using plaintext */ - get_challenge(p); - SSVALS(outbuf,smb_vwv16+1,8); - p += 8; - } - p += srvstr_push(outbuf, p, lp_workgroup(), -1, - STR_UNICODE|STR_TERMINATE|STR_NOALIGN); - DEBUG(3,("not using SPNEGO\n")); - } else { - int len = negprot_spnego(p); - - SSVALS(outbuf,smb_vwv16+1,len); - p += len; - DEBUG(3,("using SPNEGO\n")); - } - - SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */ - set_message_end(outbuf, p); - - return (smb_len(outbuf)+4); -} - -/* these are the protocol lists used for auto architecture detection: - -WinNT 3.51: -protocol [PC NETWORK PROGRAM 1.0] -protocol [XENIX CORE] -protocol [MICROSOFT NETWORKS 1.03] -protocol [LANMAN1.0] -protocol [Windows for Workgroups 3.1a] -protocol [LM1.2X002] -protocol [LANMAN2.1] -protocol [NT LM 0.12] - -Win95: -protocol [PC NETWORK PROGRAM 1.0] -protocol [XENIX CORE] -protocol [MICROSOFT NETWORKS 1.03] -protocol [LANMAN1.0] -protocol [Windows for Workgroups 3.1a] -protocol [LM1.2X002] -protocol [LANMAN2.1] -protocol [NT LM 0.12] - -Win2K: -protocol [PC NETWORK PROGRAM 1.0] -protocol [LANMAN1.0] -protocol [Windows for Workgroups 3.1a] -protocol [LM1.2X002] -protocol [LANMAN2.1] -protocol [NT LM 0.12] - -OS/2: -protocol [PC NETWORK PROGRAM 1.0] -protocol [XENIX CORE] -protocol [LANMAN1.0] -protocol [LM1.2X002] -protocol [LANMAN2.1] -*/ - -/* - * Modified to recognize the architecture of the remote machine better. - * - * This appears to be the matrix of which protocol is used by which - * MS product. - Protocol WfWg Win95 WinNT Win2K OS/2 - PC NETWORK PROGRAM 1.0 1 1 1 1 1 - XENIX CORE 2 2 - MICROSOFT NETWORKS 3.0 2 2 - DOS LM1.2X002 3 3 - MICROSOFT NETWORKS 1.03 3 - DOS LANMAN2.1 4 4 - LANMAN1.0 4 2 3 - Windows for Workgroups 3.1a 5 5 5 3 - LM1.2X002 6 4 4 - LANMAN2.1 7 5 5 - NT LM 0.12 6 8 6 - * - * tim@fsg.com 09/29/95 - * Win2K added by matty 17/7/99 - */ - -#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */ -#define ARCH_WIN95 0x2 -#define ARCH_WINNT 0x4 -#define ARCH_WIN2K 0xC /* Win2K is like NT */ -#define ARCH_OS2 0x14 /* Again OS/2 is like NT */ -#define ARCH_SAMBA 0x20 - -#define ARCH_ALL 0x3F - -/* List of supported protocols, most desired first */ -static const struct { - const char *proto_name; - const char *short_name; - int (*proto_reply_fn)(char *, char *); - int protocol_level; -} supported_protocols[] = { - {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1}, - {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1}, - {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, - {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, - {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS}, - {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE}, - {NULL,NULL,NULL,0}, -}; - -/**************************************************************************** - Reply to a negprot. -****************************************************************************/ - -int reply_negprot(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, - int dum_buffsize) -{ - int outsize = set_message(outbuf,1,0,True); - int Index=0; - int choice= -1; - int protocol; - char *p; - int bcc = SVAL(smb_buf(inbuf),-2); - int arch = ARCH_ALL; - - static BOOL done_negprot = False; - - START_PROFILE(SMBnegprot); - - if (done_negprot) { - END_PROFILE(SMBnegprot); - exit_server("multiple negprot's are not permitted"); - } - done_negprot = True; - - p = smb_buf(inbuf)+1; - while (p < (smb_buf(inbuf) + bcc)) { - Index++; - DEBUG(3,("Requested protocol [%s]\n",p)); - if (strcsequal(p,"Windows for Workgroups 3.1a")) - arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); - else if (strcsequal(p,"DOS LM1.2X002")) - arch &= ( ARCH_WFWG | ARCH_WIN95 ); - else if (strcsequal(p,"DOS LANMAN2.1")) - arch &= ( ARCH_WFWG | ARCH_WIN95 ); - else if (strcsequal(p,"NT LM 0.12")) - arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); - else if (strcsequal(p,"LANMAN2.1")) - arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); - else if (strcsequal(p,"LM1.2X002")) - arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); - else if (strcsequal(p,"MICROSOFT NETWORKS 1.03")) - arch &= ARCH_WINNT; - else if (strcsequal(p,"XENIX CORE")) - arch &= ( ARCH_WINNT | ARCH_OS2 ); - else if (strcsequal(p,"Samba")) { - arch = ARCH_SAMBA; - break; - } - - p += strlen(p) + 2; - } - - switch ( arch ) { - case ARCH_SAMBA: - set_remote_arch(RA_SAMBA); - break; - case ARCH_WFWG: - set_remote_arch(RA_WFWG); - break; - case ARCH_WIN95: - set_remote_arch(RA_WIN95); - break; - case ARCH_WINNT: - if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE) - set_remote_arch(RA_WIN2K); - else - set_remote_arch(RA_WINNT); - break; - case ARCH_WIN2K: - set_remote_arch(RA_WIN2K); - break; - case ARCH_OS2: - set_remote_arch(RA_OS2); - break; - default: - set_remote_arch(RA_UNKNOWN); - break; - } - - /* possibly reload - change of architecture */ - reload_services(True); - - /* Check for protocols, most desirable first */ - for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) { - p = smb_buf(inbuf)+1; - Index = 0; - if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) && - (supported_protocols[protocol].protocol_level >= lp_minprotocol())) - while (p < (smb_buf(inbuf) + bcc)) { - if (strequal(p,supported_protocols[protocol].proto_name)) - choice = Index; - Index++; - p += strlen(p) + 2; - } - if(choice != -1) - break; - } - - SSVAL(outbuf,smb_vwv0,choice); - if(choice != -1) { - extern fstring remote_proto; - fstrcpy(remote_proto,supported_protocols[protocol].short_name); - reload_services(True); - outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf); - DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); - } else { - DEBUG(0,("No protocol supported !\n")); - } - SSVAL(outbuf,smb_vwv0,choice); - - DEBUG( 5, ( "negprot index=%d\n", choice ) ); - - if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) { - exit_server("SMB signing is required and client negotiated a downlevel protocol"); - } - - END_PROFILE(SMBnegprot); - return(outsize); -} diff --git a/source/smbd/noquotas.c b/source/smbd/noquotas.c deleted file mode 100644 index 85caef57e1a..00000000000 --- a/source/smbd/noquotas.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - Unix SMB/CIFS implementation. - No support for quotas :-). - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* - * Needed for auto generation of proto.h. - */ - -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 */ - - /* And just to be sure we set some values that hopefully */ - /* will be larger that any possible real-world value */ - (*dfree) = (SMB_BIG_UINT)-1; - (*dsize) = (SMB_BIG_UINT)-1; - - /* As we have select not to use quotas, allways fail */ - return False; -} diff --git a/source/smbd/notify.c b/source/smbd/notify.c deleted file mode 100644 index 9adf827c794..00000000000 --- a/source/smbd/notify.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - Unix SMB/CIFS implementation. - change notify handling - Copyright (C) Andrew Tridgell 2000 - Copyright (C) Jeremy Allison 1994-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -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. -*****************************************************************************/ - -struct change_notify { - struct change_notify *next, *prev; - files_struct *fsp; - connection_struct *conn; - uint32 flags; - char request_buf[smb_size]; - void *change_data; -}; - -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, NTSTATUS error_code) -{ - char outbuf[smb_size+38]; - - memset(outbuf, '\0', sizeof(outbuf)); - construct_reply_common(inbuf, outbuf); - - ERROR_NT(error_code); - - /* - * Seems NT needs a transact command with an error code - * in it. This is a longer packet than a simple error. - */ - set_message(outbuf,18,0,False); - - if (!send_smb(smbd_server_fd(),outbuf)) - 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. -*****************************************************************************/ - -static void change_notify_remove(struct change_notify *cnbp) -{ - cnotify->remove_notify(cnbp->change_data); - DLIST_REMOVE(change_notify_list, cnbp); - ZERO_STRUCTP(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; - - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; - if (cnbp->fsp->fnum == fsp->fnum) { - change_notify_remove(cnbp); - } - } -} - -/**************************************************************************** - 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; - - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; - if(SVAL(cnbp->request_buf,smb_mid) == mid) { - change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED); - change_notify_remove(cnbp); - } - } -} - -/**************************************************************************** - 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; - - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; - /* - * We know it refers to the same directory if the connection number and - * the filename are identical. - */ - if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) { - change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED); - change_notify_remove(cnbp); - } - } -} - -/**************************************************************************** - Return true if there are pending change notifies. -****************************************************************************/ - -int change_notify_timeout(void) -{ - return cnotify->select_time; -} - -/**************************************************************************** - Process the change notify queue. Note that this is only called as root. - 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; - uint16 vuid; - - for (cnbp=change_notify_list; cnbp; cnbp=next) { - 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); - } - } - - return (change_notify_list != NULL); -} - -/**************************************************************************** - 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; - - if((cnbp = (struct change_notify *)malloc(sizeof(*cnbp))) == NULL) { - DEBUG(0,("change_notify_set: malloc fail !\n" )); - return -1; - } - - ZERO_STRUCTP(cnbp); - - memcpy(cnbp->request_buf, inbuf, smb_size); - cnbp->fsp = fsp; - cnbp->conn = conn; - cnbp->flags = flags; - cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags); - - if (!cnbp->change_data) { - SAFE_FREE(cnbp); - return False; - } - - DLIST_ADD(change_notify_list, cnbp); - - /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); - - return True; -} - -/**************************************************************************** - Initialise the change notify subsystem. -****************************************************************************/ - -BOOL init_change_notify(void) -{ -#if HAVE_KERNEL_CHANGE_NOTIFY - if (lp_kernel_change_notify()) - cnotify = kernel_notify_init(); -#endif - if (!cnotify) cnotify = hash_notify_init(); - - if (!cnotify) { - DEBUG(0,("Failed to init change notify system\n")); - return False; - } - - return True; -} diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c deleted file mode 100644 index ec414454f9e..00000000000 --- a/source/smbd/notify_hash.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - Unix SMB/CIFS implementation. - change notify handling - hash based implementation - Copyright (C) Jeremy Allison 1994-1998 - Copyright (C) Andrew Tridgell 2000 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -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) -{ - SMB_STRUCT_STAT st; - pstring full_name; - char *p; - const char *fname; - size_t remaining_len; - size_t fullname_len; - void *dp; - - ZERO_STRUCTP(data); - - if(SMB_VFS_STAT(conn,path, &st) == -1) - return False; - - data->modify_time = st.st_mtime; - data->status_time = st.st_ctime; - - if (old_data) { - /* - * Shortcut to avoid directory scan if the time - * has changed - we always must return true then. - */ - if (old_data->modify_time != data->modify_time || - old_data->status_time != data->status_time ) { - return True; - } - } - - /* - * If we are to watch for changes that are only stored - * in inodes of files, not in the directory inode, we must - * scan the directory and produce a unique identifier with - * which we can determine if anything changed. We use the - * modify and change times from all the files in the - * directory, added together (ignoring wrapping if it's - * larger than the max time_t value). - */ - - dp = OpenDir(conn, path, True); - if (dp == NULL) - return False; - - data->num_entries = 0; - - pstrcpy(full_name, path); - pstrcat(full_name, "/"); - - fullname_len = strlen(full_name); - remaining_len = sizeof(full_name) - fullname_len - 1; - p = &full_name[fullname_len]; - - while ((fname = ReadDirName(dp))) { - if(strequal(fname, ".") || strequal(fname, "..")) - continue; - - data->num_entries++; - safe_strcpy(p, fname, remaining_len); - - ZERO_STRUCT(st); - - /* - * Do the stat - but ignore errors. - */ - SMB_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, (const 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); - - return True; -} - -/**************************************************************************** - 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; - - data.last_check_time = time(NULL); - - return (void *)memdup(&data, sizeof(data)); -} - -/**************************************************************************** - 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 (!change_to_user(conn,vuid)) - return True; - if (!set_current_service(conn,True)) { - change_to_root_user(); - return True; - } - - if (!notify_hash(conn, path, flags, &data2, data) || - data2.modify_time != data->modify_time || - data2.status_time != data->status_time || - data2.total_time != data->total_time || - 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; - - change_to_root_user(); - - return False; -} - -/**************************************************************************** - Remove a change notify data structure. -*****************************************************************************/ - -static void hash_remove_notify(void *datap) -{ - free(datap); -} - -/**************************************************************************** - Setup hash based change notify. -****************************************************************************/ - -struct cnotify_fns *hash_notify_init(void) -{ - static struct cnotify_fns cnotify; - - cnotify.register_notify = hash_register_notify; - cnotify.check_notify = hash_check_notify; - cnotify.remove_notify = hash_remove_notify; - cnotify.select_time = lp_change_notify_timeout(); - - return &cnotify; -} - -/* - change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess); - change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR); - - chain_size = 0; - file_chain_reset(); - - uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : - SVAL(cnbp->request_buf,smb_uid); -*/ diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c deleted file mode 100644 index 8fcc18a09f9..00000000000 --- a/source/smbd/notify_kernel.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 3.0 - change notify handling - linux kernel based implementation - Copyright (C) Andrew Tridgell 2000 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#if HAVE_KERNEL_CHANGE_NOTIFY - -#define FD_PENDING_SIZE 20 -static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE]; -static SIG_ATOMIC_T signals_received; - -#ifndef DN_ACCESS -#define DN_ACCESS 0x00000001 /* File accessed in directory */ -#define DN_MODIFY 0x00000002 /* File modified in directory */ -#define DN_CREATE 0x00000004 /* File created in directory */ -#define DN_DELETE 0x00000008 /* File removed from directory */ -#define DN_RENAME 0x00000010 /* File renamed in directory */ -#define DN_ATTRIB 0x00000020 /* File changed attribute */ -#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ -#endif - - -#ifndef RT_SIGNAL_NOTIFY -#define RT_SIGNAL_NOTIFY (SIGRTMIN+2) -#endif - -#ifndef F_SETSIG -#define F_SETSIG 10 -#endif - -#ifndef F_NOTIFY -#define F_NOTIFY 1026 -#endif - -/**************************************************************************** - This is the structure to keep the information needed to - determine if a directory has changed. -*****************************************************************************/ - -struct change_data { - int directory_handle; -}; - -/**************************************************************************** - The signal handler for change notify. - The Linux kernel has a bug in that we should be able to block any - further delivery of RT signals until the kernel_check_notify() function - unblocks them, but it seems that any signal mask we're setting here is - being overwritten on exit from this handler. I should create a standalone - test case for the kernel hackers. JRA. -*****************************************************************************/ - -static void signal_handler(int sig, siginfo_t *info, void *unused) -{ - if (signals_received < FD_PENDING_SIZE - 1) { - fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd; - signals_received++; - } /* Else signal is lost. */ - sys_select_signal(); -} - -/**************************************************************************** - Check if a change notify should be issued. - time non-zero means timeout check (used for hash). Ignore this (async method - where time is zero will be used instead). -*****************************************************************************/ - -static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t) -{ - struct change_data *data = (struct change_data *)datap; - int i; - BOOL ret = False; - - if (t) - return False; - - BlockSignals(True, RT_SIGNAL_NOTIFY); - for (i = 0; i < signals_received; i++) { - if (data->directory_handle == (int)fd_pending_array[i]) { - DEBUG(3,("kernel_check_notify: kernel change notify on %s fd[%d]=%d (signals_received=%d)\n", - path, i, (int)fd_pending_array[i], (int)signals_received )); - - close((int)fd_pending_array[i]); - fd_pending_array[i] = (SIG_ATOMIC_T)-1; - if (signals_received - i - 1) { - memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1], - sizeof(SIG_ATOMIC_T)*(signals_received-i-1)); - } - data->directory_handle = -1; - signals_received--; - ret = True; - break; - } - } - BlockSignals(False, RT_SIGNAL_NOTIFY); - return ret; -} - -/**************************************************************************** - Remove a change notify data structure. -*****************************************************************************/ - -static void kernel_remove_notify(void *datap) -{ - struct change_data *data = (struct change_data *)datap; - int fd = data->directory_handle; - if (fd != -1) { - int i; - BlockSignals(True, RT_SIGNAL_NOTIFY); - for (i = 0; i < signals_received; i++) { - if (fd == (int)fd_pending_array[i]) { - fd_pending_array[i] = (SIG_ATOMIC_T)-1; - if (signals_received - i - 1) { - memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1], - sizeof(SIG_ATOMIC_T)*(signals_received-i-1)); - } - data->directory_handle = -1; - signals_received--; - break; - } - } - close(fd); - BlockSignals(False, RT_SIGNAL_NOTIFY); - } - SAFE_FREE(data); - DEBUG(3,("kernel_remove_notify: fd=%d\n", fd)); -} - -/**************************************************************************** - Register a change notify request. -*****************************************************************************/ - -static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags) -{ - struct change_data data; - int fd; - unsigned long kernel_flags; - - fd = sys_open(path,O_RDONLY, 0); - - if (fd == -1) { - DEBUG(3,("Failed to open directory %s for change notify\n", path)); - return NULL; - } - - if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) { - DEBUG(3,("Failed to set signal handler for change notify\n")); - return NULL; - } - - kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion changes everything! */ - if (flags & FILE_NOTIFY_CHANGE_FILE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME|DN_DELETE; - if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS; - if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE; - if (flags & FILE_NOTIFY_CHANGE_SECURITY) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME|DN_DELETE; - - if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) { - DEBUG(3,("Failed to set async flag for change notify\n")); - return NULL; - } - - data.directory_handle = fd; - - DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) fd=%d\n", - path, (int)flags, (int)kernel_flags, fd)); - - return (void *)memdup(&data, sizeof(data)); -} - -/**************************************************************************** - See if the kernel supports change notify. -****************************************************************************/ - -static BOOL kernel_notify_available(void) -{ - int fd, ret; - fd = open("/tmp", O_RDONLY); - if (fd == -1) - return False; /* uggh! */ - ret = sys_fcntl_long(fd, F_NOTIFY, 0); - close(fd); - return ret == 0; -} - -/**************************************************************************** - Setup kernel based change notify. -****************************************************************************/ - -struct cnotify_fns *kernel_notify_init(void) -{ - static struct cnotify_fns cnotify; - struct sigaction act; - - ZERO_STRUCT(act); - - act.sa_handler = NULL; - act.sa_sigaction = signal_handler; - act.sa_flags = SA_SIGINFO; - sigemptyset( &act.sa_mask ); - if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) { - DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n")); - return NULL; - } - - if (!kernel_notify_available()) - return NULL; - - cnotify.register_notify = kernel_register_notify; - cnotify.check_notify = kernel_check_notify; - cnotify.remove_notify = kernel_remove_notify; - cnotify.select_time = -1; - - /* the signal can start off blocked due to a bug in bash */ - BlockSignals(False, RT_SIGNAL_NOTIFY); - - return &cnotify; -} - -#else - void notify_kernel_dummy(void) {} -#endif /* HAVE_KERNEL_CHANGE_NOTIFY */ diff --git a/source/smbd/ntquotas.c b/source/smbd/ntquotas.c deleted file mode 100644 index 555f32d773f..00000000000 --- a/source/smbd/ntquotas.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - Unix SMB/CIFS implementation. - NT QUOTA suppport - Copyright (C) Stefan (metze) Metzmacher 2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_QUOTA - -static SMB_BIG_UINT limit_nt2unix(SMB_BIG_UINT in, SMB_BIG_UINT bsize) -{ - SMB_BIG_UINT ret = (SMB_BIG_UINT)0; - - ret = (SMB_BIG_UINT)(in/bsize); - if (in>0 && ret==0) { - /* we have to make sure that a overflow didn't set NO_LIMIT */ - ret = (SMB_BIG_UINT)1; - } - - if (in == SMB_NTQUOTAS_NO_LIMIT) - ret = SMB_QUOTAS_NO_LIMIT; - else if (in == SMB_NTQUOTAS_NO_SPACE) - ret = SMB_QUOTAS_NO_SPACE; - else if (in == SMB_NTQUOTAS_NO_ENTRY) - ret = SMB_QUOTAS_NO_LIMIT; - - return ret; -} - -static SMB_BIG_UINT limit_unix2nt(SMB_BIG_UINT in, SMB_BIG_UINT bsize) -{ - SMB_BIG_UINT ret = (SMB_BIG_UINT)0; - - ret = (SMB_BIG_UINT)(in*bsize); - - if (ret < in) { - /* we overflow */ - ret = SMB_NTQUOTAS_NO_LIMIT; - } - - if (in == SMB_QUOTAS_NO_LIMIT) - ret = SMB_NTQUOTAS_NO_LIMIT; - - return ret; -} - -static SMB_BIG_UINT limit_blk2inodes(SMB_BIG_UINT in) -{ - SMB_BIG_UINT ret = (SMB_BIG_UINT)0; - - ret = (SMB_BIG_UINT)(in/2); - - if (ret == 0 && in != 0) - ret = (SMB_BIG_UINT)1; - - return ret; -} - -int vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, SMB_NTQUOTA_STRUCT *qt) -{ - int ret; - SMB_DISK_QUOTA D; - unid_t id; - - ZERO_STRUCT(D); - - if (!fsp||!fsp->conn||!qt) - return (-1); - - ZERO_STRUCT(*qt); - - id.uid = -1; - - if (psid && !NT_STATUS_IS_OK(sid_to_uid(psid, &id.uid))) { - DEBUG(0,("sid_to_uid: failed, SID[%s]\n", - sid_string_static(psid))); - } - - ret = SMB_VFS_GET_QUOTA(fsp->conn, qtype, id, &D); - - if (psid) - qt->sid = *psid; - - if (ret!=0) { - return ret; - } - - qt->usedspace = (SMB_BIG_UINT)D.curblocks*D.bsize; - qt->softlim = limit_unix2nt(D.softlimit, D.bsize); - qt->hardlim = limit_unix2nt(D.hardlimit, D.bsize); - qt->qflags = D.qflags; - - - return 0; -} - -int vfs_set_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, DOM_SID *psid, SMB_NTQUOTA_STRUCT *qt) -{ - int ret; - SMB_DISK_QUOTA D; - unid_t id; - ZERO_STRUCT(D); - - if (!fsp||!fsp->conn||!qt) - return (-1); - - id.uid = -1; - - D.bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; - - D.softlimit = limit_nt2unix(qt->softlim,D.bsize); - D.hardlimit = limit_nt2unix(qt->hardlim,D.bsize); - D.qflags = qt->qflags; - - D.isoftlimit = limit_blk2inodes(D.softlimit); - D.ihardlimit = limit_blk2inodes(D.hardlimit); - - if (psid && !NT_STATUS_IS_OK(sid_to_uid(psid, &id.uid))) { - DEBUG(0,("sid_to_uid: failed, SID[%s]\n", - sid_string_static(psid))); - } - - ret = SMB_VFS_SET_QUOTA(fsp->conn, qtype, id, &D); - - return ret; -} - -static BOOL allready_in_quota_list(SMB_NTQUOTA_LIST *qt_list, uid_t uid) -{ - SMB_NTQUOTA_LIST *tmp_list = NULL; - - if (!qt_list) - return False; - - for (tmp_list=qt_list;tmp_list!=NULL;tmp_list=tmp_list->next) { - if (tmp_list->uid == uid) { - return True; - } - } - - return False; -} - -int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list) -{ - struct passwd *usr; - TALLOC_CTX *mem_ctx = NULL; - - if (!fsp||!fsp->conn||!qt_list) - return (-1); - - *qt_list = NULL; - - if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) { - DEBUG(0,("talloc_init() failed\n")); - return (-1); - } - - sys_setpwent(); - while ((usr = sys_getpwent()) != NULL) { - SMB_NTQUOTA_STRUCT tmp_qt; - SMB_NTQUOTA_LIST *tmp_list_ent; - DOM_SID sid; - - ZERO_STRUCT(tmp_qt); - - if (allready_in_quota_list((*qt_list),usr->pw_uid)) { - DEBUG(5,("record for uid[%ld] allready in the list\n",(long)usr->pw_uid)); - continue; - } - - if (!NT_STATUS_IS_OK(uid_to_sid(&sid, usr->pw_uid))) { - DEBUG(0,("uid_to_sid failed for %ld\n",(long)usr->pw_uid)); - continue; - } - - if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &tmp_qt)!=0) { - DEBUG(5,("no quota entry for sid[%s] path[%s]\n", - sid_string_static(&sid),fsp->conn->connectpath)); - continue; - } - - DEBUG(15,("quota entry for id[%s] path[%s]\n", - sid_string_static(&sid),fsp->conn->connectpath)); - - if ((tmp_list_ent=(SMB_NTQUOTA_LIST *)talloc_zero(mem_ctx,sizeof(SMB_NTQUOTA_LIST)))==NULL) { - DEBUG(0,("talloc_zero() failed\n")); - *qt_list = NULL; - talloc_destroy(mem_ctx); - return (-1); - } - - if ((tmp_list_ent->quotas=(SMB_NTQUOTA_STRUCT *)talloc_zero(mem_ctx,sizeof(SMB_NTQUOTA_STRUCT)))==NULL) { - DEBUG(0,("talloc_zero() failed\n")); - *qt_list = NULL; - talloc_destroy(mem_ctx); - return (-1); - } - - tmp_list_ent->uid = usr->pw_uid; - memcpy(tmp_list_ent->quotas,&tmp_qt,sizeof(tmp_qt)); - tmp_list_ent->mem_ctx = mem_ctx; - - DLIST_ADD((*qt_list),tmp_list_ent); - - } - sys_endpwent(); - - return 0; -} - -void *init_quota_handle(TALLOC_CTX *mem_ctx) -{ - SMB_NTQUOTA_HANDLE *qt_handle; - - if (!mem_ctx) - return False; - - qt_handle = (SMB_NTQUOTA_HANDLE *)talloc_zero(mem_ctx,sizeof(SMB_NTQUOTA_HANDLE)); - if (qt_handle==NULL) { - DEBUG(0,("talloc_zero() failed\n")); - return NULL; - } - - return (void *)qt_handle; -} - -void destroy_quota_handle(void **pqt_handle) -{ - SMB_NTQUOTA_HANDLE *qt_handle = NULL; - if (!pqt_handle||!(*pqt_handle)) - return; - - qt_handle = (*pqt_handle); - - - if (qt_handle->quota_list) - free_ntquota_list(&qt_handle->quota_list); - - qt_handle->quota_list = NULL; - qt_handle->tmp_list = NULL; - qt_handle = NULL; - - return; -} - diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c deleted file mode 100644 index 018f6bbbece..00000000000 --- a/source/smbd/nttrans.c +++ /dev/null @@ -1,2780 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB NT transaction handling - Copyright (C) Jeremy Allison 1994-1998 - Copyright (C) Stefan (metze) Metzmacher 2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -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 struct current_user current_user; - -static const char *known_nt_pipes[] = { - "\\LANMAN", - "\\srvsvc", - "\\samr", - "\\wkssvc", - "\\NETLOGON", - "\\ntlsa", - "\\ntsvcs", - "\\lsass", - "\\lsarpc", - "\\winreg", - "\\spoolss", - "\\netdfs", - "\\rpcecho", - "\\epmapper", - NULL -}; - -/* Map generic permissions to file object specific permissions */ - -struct generic_mapping file_generic_mapping = { - FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_GENERIC_ALL -}; - -static char *nttrans_realloc(char **ptr, size_t size) -{ - char *tptr = NULL; - if (ptr==NULL) - smb_panic("nttrans_realloc() called with NULL ptr\n"); - - tptr = Realloc_zero(*ptr, size); - if(tptr == NULL) { - *ptr = NULL; - return NULL; - } - - *ptr = tptr; - - return tptr; -} - - -/**************************************************************************** - Send the required number of replies back. - We assume all fields other than the data fields are - set correctly for the type of call. - HACK ! Always assumes smb_setup field is zero. -****************************************************************************/ - -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; - 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 = 3; - int data_alignment_offset = 0; - - /* - * Initially set the wcnt area to be 18 - this is true for all - * transNT replies. - */ - - set_message(outbuf,18,0,True); - - if (NT_STATUS_V(nt_error)) - ERROR_NT(nt_error); - - /* - * 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_nt_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 a four byte - * boundary (2 bytes for data len, one byte pad). - * NT 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. - */ - - total_sent_thistime = MIN(total_sent_thistime, useable_space); - - set_message(outbuf, 18, total_sent_thistime, True); - - /* - * Set total params and data to be sent. - */ - - SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize); - SIVAL(outbuf,smb_ntr_TotalDataCount,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); - - SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime); - - if(params_sent_thistime == 0) { - SIVAL(outbuf,smb_ntr_ParameterOffset,0); - SIVAL(outbuf,smb_ntr_ParameterDisplacement,0); - } else { - /* - * smb_ntr_ParameterOffset 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. - */ - - SIVAL(outbuf,smb_ntr_ParameterOffset, - ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - /* - * Absolute displacement of param bytes sent in this packet. - */ - - SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params); - } - - /* - * Deal with the data portion. - */ - - SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime); - - if(data_sent_thistime == 0) { - SIVAL(outbuf,smb_ntr_DataOffset,0); - SIVAL(outbuf,smb_ntr_DataDisplacement, 0); - } else { - /* - * The offset of the data bytes is the offset of the - * parameter bytes plus the number of parameters being sent this time. - */ - - SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); - SIVAL(outbuf,smb_ntr_DataDisplacement, 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,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("nt_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_nt_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_nt_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } - - return 0; -} - -/**************************************************************************** - Save case statics. -****************************************************************************/ - -static BOOL saved_case_sensitive; -static BOOL saved_case_preserve; -static BOOL saved_short_case_preserve; - -/**************************************************************************** - Save case semantics. -****************************************************************************/ - -static void set_posix_case_semantics(uint32 file_attributes) -{ - if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) - return; - - saved_case_sensitive = case_sensitive; - saved_case_preserve = case_preserve; - saved_short_case_preserve = short_case_preserve; - - /* Set to POSIX. */ - case_sensitive = True; - case_preserve = True; - short_case_preserve = True; -} - -/**************************************************************************** - Restore case semantics. -****************************************************************************/ - -static void restore_case_semantics(uint32 file_attributes) -{ - if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) - return; - - case_sensitive = saved_case_sensitive; - case_preserve = saved_case_preserve; - short_case_preserve = saved_short_case_preserve; -} - -/**************************************************************************** - Utility function to map create disposition. -****************************************************************************/ - -static int map_create_disposition( uint32 create_disposition) -{ - int ret; - - switch( create_disposition ) { - case FILE_CREATE: - /* create if not exist, fail if exist */ - ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL); - break; - case FILE_SUPERSEDE: - case FILE_OVERWRITE_IF: - /* create if not exist, trunc if exist */ - ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE); - break; - case FILE_OPEN: - /* fail if not exist, open if exists */ - ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN); - break; - case FILE_OPEN_IF: - /* create if not exist, open if exists */ - ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN); - break; - case FILE_OVERWRITE: - /* fail if not exist, truncate if exists */ - ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE); - break; - default: - DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n", - create_disposition )); - return -1; - } - - DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n", - (unsigned long)create_disposition, ret )); - - return ret; -} - -/**************************************************************************** - Utility function to map share modes. -****************************************************************************/ - -static int map_share_mode( char *fname, uint32 create_options, - uint32 *desired_access, uint32 share_access, uint32 file_attributes) -{ - int smb_open_mode = -1; - uint32 original_desired_access = *desired_access; - - /* - * Convert GENERIC bits to specific bits. - */ - - se_map_generic(desired_access, &file_generic_mapping); - - switch( *desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) { - case FILE_READ_DATA: - smb_open_mode = DOS_OPEN_RDONLY; - break; - case FILE_WRITE_DATA: - case FILE_APPEND_DATA: - case FILE_WRITE_DATA|FILE_APPEND_DATA: - smb_open_mode = DOS_OPEN_WRONLY; - break; - case FILE_READ_DATA|FILE_WRITE_DATA: - case FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA: - case FILE_READ_DATA|FILE_APPEND_DATA: - smb_open_mode = DOS_OPEN_RDWR; - break; - } - - /* - * NB. For DELETE_ACCESS we should really check the - * directory permissions, as that is what controls - * delete, and for WRITE_DAC_ACCESS we should really - * check the ownership, as that is what controls the - * chmod. Note that this is *NOT* a security hole (this - * note is for you, Andrew) as we are not *allowing* - * the access at this point, the actual unlink or - * chown or chmod call would do this. We are just helping - * clients out by telling them if they have a hope - * of any of this succeeding. POSIX acls may still - * deny the real call. JRA. - */ - - if (smb_open_mode == -1) { - - if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS| - FILE_EXECUTE|FILE_READ_ATTRIBUTES| - FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS| - FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) { - smb_open_mode = DOS_OPEN_RDONLY; - } else if(*desired_access == 0) { - - /* - * JRA - NT seems to sometimes send desired_access as zero. play it safe - * and map to a stat open. - */ - - smb_open_mode = DOS_OPEN_RDONLY; - - } else { - DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n", - (unsigned long)*desired_access, fname)); - return -1; - } - } - - /* - * Set the special bit that means allow share delete. - * This is held outside the normal share mode bits at 1<<15. - * JRA. - */ - - if(share_access & FILE_SHARE_DELETE) { - smb_open_mode |= ALLOW_SHARE_DELETE; - DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode)); - } - - if(*desired_access & DELETE_ACCESS) { - DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode)); - } - - /* - * We need to store the intent to open for Delete. This - * is what determines if a delete on close flag can be set. - * This is the wrong way (and place) to store this, but for 2.2 this - * is the only practical way. JRA. - */ - - if (create_options & FILE_DELETE_ON_CLOSE) { - /* - * W2K3 bug compatibility mode... To set delete on close - * the redirector must have *specifically* set DELETE_ACCESS - * in the desired_access field. Just asking for GENERIC_ALL won't do. JRA. - */ - - if (!(original_desired_access & DELETE_ACCESS)) { - DEBUG(5,("map_share_mode: FILE_DELETE_ON_CLOSE requested without \ -DELETE_ACCESS for file %s. (desired_access = 0x%lx)\n", - fname, (unsigned long)*desired_access)); - return -1; - } - /* Implicit delete access is *NOT* 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. */ - switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) { - case FILE_SHARE_READ: - smb_open_mode |= SET_DENY_MODE(DENY_WRITE); - break; - case FILE_SHARE_WRITE: - smb_open_mode |= SET_DENY_MODE(DENY_READ); - break; - case (FILE_SHARE_READ|FILE_SHARE_WRITE): - smb_open_mode |= SET_DENY_MODE(DENY_NONE); - break; - case FILE_SHARE_NONE: - smb_open_mode |= SET_DENY_MODE(DENY_ALL); - break; - } - - /* - * Handle an O_SYNC request. - */ - - if(file_attributes & FILE_FLAG_WRITE_THROUGH) - smb_open_mode |= FILE_SYNC_OPENMODE; - - 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; -} - -/**************************************************************************** - Reply to an NT create and X call on a pipe. -****************************************************************************/ - -static int nt_open_pipe(char *fname, connection_struct *conn, - char *inbuf, char *outbuf, int *ppnum) -{ - smb_np_struct *p = NULL; - - uint16 vuid = SVAL(inbuf, smb_uid); - int i; - - DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname)); - - /* See if it is one we want to handle. */ - - if (lp_disable_spoolss() && strequal(fname, "\\spoolss")) - return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); - - for( i = 0; known_nt_pipes[i]; i++ ) - if( strequal(fname,known_nt_pipes[i])) - break; - - if ( known_nt_pipes[i] == NULL ) - return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); - - /* Strip \\ off the name. */ - fname++; - - DEBUG(3,("nt_open_pipe: Known pipe %s opening.\n", fname)); - - p = open_rpc_pipe_p(fname, conn, vuid); - if (!p) - return(ERROR_DOS(ERRSRV,ERRnofids)); - - *ppnum = p->pnum; - - return 0; -} - -/**************************************************************************** - Reply to an NT create and X call for pipes. -****************************************************************************/ - -static int do_ntcreate_pipe_open(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - pstring fname; - int ret; - int pnum = -1; - char *p = NULL; - - srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); - - if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) - return ret; - - /* - * Deal with pipe return. - */ - - set_message(outbuf,34,0,True); - - p = outbuf + smb_vwv2; - p++; - SSVAL(p,0,pnum); - p += 2; - SIVAL(p,0,FILE_WAS_OPENED); - p += 4; - p += 32; - SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */ - p += 20; - /* File type. */ - SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE); - /* Device state. */ - SSVAL(p,2, 0x5FF); /* ? */ - - DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname)); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - Reply to an NT create and X call. -****************************************************************************/ - -int reply_ntcreate_and_X(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - int result; - pstring fname; - enum FAKE_FILE_TYPE fake_file_type = FAKE_FILE_TYPE_NONE; - uint32 flags = IVAL(inbuf,smb_ntcreate_Flags); - uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess); - uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes); - uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess); - uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition); - uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions); - uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid); - SMB_BIG_UINT allocation_size = 0; - int smb_ofun; - int smb_open_mode; - /* Breakout the oplock request bits so we can set the - reply bits separately. */ - int oplock_request = 0; - int fmode=0,rmode=0; - SMB_OFF_T file_len = 0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp=NULL; - char *p = NULL; - time_t c_time; - BOOL extended_oplock_granted = False; - NTSTATUS status; - - START_PROFILE(SMBntcreateX); - - DEBUG(10,("reply_ntcreateX: flags = 0x%x, desired_access = 0x%x \ -file_attributes = 0x%x, share_access = 0x%x, create_disposition = 0x%x \ -create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attributes, - share_access, create_disposition, - create_options, root_dir_fid )); - - /* If it's an IPC, use the pipe handler. */ - - if (IS_IPC(conn)) { - if (lp_nt_pipe_support()) { - END_PROFILE(SMBntcreateX); - return do_ntcreate_pipe_open(conn,inbuf,outbuf,length,bufsize); - } else { - END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - } - } - - if (create_options & FILE_OPEN_BY_FILE_ID) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); - } - - /* - * We need to construct the open_and_X ofun value from the - * NT values, as that's what our code is structured to accept. - */ - - if((smb_ofun = map_create_disposition( create_disposition )) == -1) { - END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - } - - /* - * 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(!dir_fsp) { - END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRbadfid)); - } - - if(!dir_fsp->is_directory) { - - srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(status); - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( strchr_m(fname, ':')) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } - - /* - we need to handle the case when we get a - relative open relative to a file and the - pathname is blank - this is a reopen! - (hint from demyn plantenberg) - */ - - END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRbadfid)); - } - - /* - * Copy in the base directory name. - */ - - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); - - /* - * Ensure it ends in a '\'. - */ - - if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') { - pstrcat(fname, "\\"); - dir_name_len++; - } - - srvstr_get_path(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(status); - } - } else { - srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(status); - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( strchr_m(fname, ':')) { - -#ifdef HAVE_SYS_QUOTAS - if ((fake_file_type=is_fake_file(fname))!=FAKE_FILE_TYPE_NONE) { - /* - * here we go! support for changing the disk quotas --metze - * - * we need to fake up to open this MAGIC QUOTA file - * and return a valid FID - * - * w2k close this file directly after openening - * xp also tries a QUERY_FILE_INFO on the file and then close it - */ - } else { -#endif - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); -#ifdef HAVE_SYS_QUOTAS - } -#endif - } - } - - /* - * Now contruct the smb_open_mode value from the filename, - * desired access and the share access. - */ - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - if((smb_open_mode = map_share_mode(fname, create_options, &desired_access, - share_access, - file_attributes)) == -1) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - if (oplock_request) { - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; - } - - /* - * Ordinary file or directory. - */ - - /* - * Check if POSIX semantics are wanted. - */ - - set_posix_case_semantics(file_attributes); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - /* - * If it's a request for a directory open, deal with it separately. - */ - - if(create_options & FILE_DIRECTORY_FILE) { - oplock_request = 0; - - /* Can't open a temp directory. IFS kit test. */ - if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - - restore_case_semantics(file_attributes); - - if(!fsp) { - END_PROFILE(SMBntcreateX); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - } else { - /* - * Ordinary file case. - */ - - /* NB. We have a potential bug here. If we - * cause an oplock break to ourselves, then we - * could end up processing filename related - * SMB requests whilst we await the oplock - * break response. As we may have changed the - * filename case semantics to be POSIX-like, - * this could mean a filename request could - * fail when it should succeed. This is a rare - * condition, but eventually we must arrange - * to restore the correct case semantics - * before issuing an oplock break request to - * our client. JRA. */ - - if (fake_file_type==FAKE_FILE_TYPE_NONE) { - fsp = open_file_shared1(conn,fname,&sbuf, - desired_access, - smb_open_mode, - smb_ofun,file_attributes,oplock_request, - &rmode,&smb_action); - } else { - /* to open a fake_file --metze */ - fsp = open_fake_file_shared1(fake_file_type,conn,fname,&sbuf, - desired_access, - smb_open_mode, - smb_ofun,file_attributes, oplock_request, - &rmode,&smb_action); - } - - if (!fsp) { - /* We cheat here. There are two cases we - * care about. One is a directory rename, - * where the NT client will attempt to - * open the source directory for - * DELETE access. Note that when the - * NT client does this it does *not* - * set the directory bit in the - * request packet. This is translated - * into a read/write open - * request. POSIX states that any open - * for write request on a directory - * will generate an EISDIR error, so - * we can catch this here and open a - * pseudo handle that is flagged as a - * directory. The second is an open - * for a permissions read only, which - * we handle in the open_file_stat case. JRA. - */ - - if(errno == EISDIR) { - - /* - * Fail the open if it was explicitly a non-directory file. - */ - - 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_NT(NT_STATUS_FILE_IS_A_DIRECTORY); - } - - oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - - if(!fsp) { - restore_case_semantics(file_attributes); - END_PROFILE(SMBntcreateX); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - } else { - - restore_case_semantics(file_attributes); - END_PROFILE(SMBntcreateX); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - } - } - - restore_case_semantics(file_attributes); - - file_len = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) - fmode = FILE_ATTRIBUTE_NORMAL; - if (!fsp->is_directory && (fmode & aDIR)) { - close_file(fsp,False); - END_PROFILE(SMBntcreateX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* Save the requested allocation size. */ - allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize); -#ifdef LARGE_SMB_OFF_T - allocation_size |= (((SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32); -#endif - if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) { - fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); - if (fsp->is_directory) { - close_file(fsp,False); - END_PROFILE(SMBntcreateX); - /* Can't set allocation size on a directory. */ - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,False); - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_DISK_FULL); - } - } else { - fsp->initial_allocation_size = SMB_ROUNDUP(((SMB_BIG_UINT)file_len),SMB_ROUNDUP_ALLOCATION_SIZE); - } - - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - extended_oplock_granted = True; - - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - extended_oplock_granted = True; - -#if 0 - /* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */ - set_message(outbuf,42,0,True); -#else - set_message(outbuf,34,0,True); -#endif - - p = outbuf + smb_vwv2; - - /* - * Currently as we don't support level II oplocks we just report - * exclusive & batch here. - */ - - if (extended_oplock_granted) { - if (flags & REQUEST_BATCH_OPLOCK) { - SCVAL(p,0, BATCH_OPLOCK_RETURN); - } else { - SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN); - } - } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) { - SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); - } else { - SCVAL(p,0,NO_OPLOCK_RETURN); - } - - p++; - SSVAL(p,0,fsp->fnum); - p += 2; - if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN)) - SIVAL(p,0,FILE_WAS_SUPERSEDED); - else - SIVAL(p,0,smb_action); - p += 4; - - /* Create time. */ - c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); - - if (lp_dos_filetime_resolution(SNUM(conn))) { - c_time &= ~1; - sbuf.st_atime &= ~1; - sbuf.st_mtime &= ~1; - sbuf.st_mtime &= ~1; - } - - put_long_date(p,c_time); - p += 8; - put_long_date(p,sbuf.st_atime); /* access time */ - p += 8; - put_long_date(p,sbuf.st_mtime); /* write time */ - p += 8; - put_long_date(p,sbuf.st_mtime); /* change time */ - p += 8; - SIVAL(p,0,fmode); /* File Attributes. */ - p += 4; - SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); - p += 8; - SOFF_T(p,0,file_len); - p += 8; - if (flags & EXTENDED_RESPONSE_REQUIRED) - SSVAL(p,2,0x7); - p += 4; - SCVAL(p,0,fsp->is_directory ? 1 : 0); - - DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name)); - - result = chain_reply(inbuf,outbuf,length,bufsize); - END_PROFILE(SMBntcreateX); - return result; -} - -/**************************************************************************** - Reply to a NT_TRANSACT_CREATE call to open a pipe. -****************************************************************************/ - -static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - pstring fname; - char *params = *ppparams; - int ret; - int pnum = -1; - char *p = NULL; - NTSTATUS status; - - /* - * Ensure minimum number of parameters sent. - */ - - if(parameter_count < 54) { - DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)parameter_count)); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) - return ret; - - /* Realloc the size of parameters and data we will return */ - params = nttrans_realloc(ppparams, 69); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - p = params; - SCVAL(p,0,NO_OPLOCK_RETURN); - - p += 2; - SSVAL(p,0,pnum); - p += 2; - SIVAL(p,0,FILE_WAS_OPENED); - p += 8; - - p += 32; - SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */ - p += 20; - /* File type. */ - SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE); - /* Device state. */ - SSVAL(p,2, 0x5FF); /* ? */ - - DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); - - /* Send the required number of replies */ - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); - - return -1; -} - -/**************************************************************************** - Internal fn to set security descriptors. -****************************************************************************/ - -static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent) -{ - prs_struct pd; - SEC_DESC *psd = NULL; - TALLOC_CTX *mem_ctx; - BOOL ret; - - if (sd_len == 0) { - return NT_STATUS_OK; - } - - /* - * Init the parse struct we will unmarshall from. - */ - - if ((mem_ctx = talloc_init("set_sd")) == NULL) { - DEBUG(0,("set_sd: talloc_init failed.\n")); - return NT_STATUS_NO_MEMORY; - } - - prs_init(&pd, 0, mem_ctx, UNMARSHALL); - - /* - * Setup the prs_struct to point at the memory we just - * allocated. - */ - - prs_give_memory( &pd, data, sd_len, False); - - /* - * Finally, unmarshall from the data buffer. - */ - - if(!sec_io_desc( "sd data", &psd, &pd, 1)) { - DEBUG(0,("set_sd: Error in unmarshalling security descriptor.\n")); - /* - * Return access denied for want of a better error message.. - */ - talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - - if (psd->off_owner_sid==0) - security_info_sent &= ~OWNER_SECURITY_INFORMATION; - if (psd->off_grp_sid==0) - security_info_sent &= ~GROUP_SECURITY_INFORMATION; - if (psd->off_sacl==0) - security_info_sent &= ~SACL_SECURITY_INFORMATION; - if (psd->off_dacl==0) - security_info_sent &= ~DACL_SECURITY_INFORMATION; - - ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fd, security_info_sent, psd); - - if (!ret) { - talloc_destroy(mem_ctx); - return NT_STATUS_ACCESS_DENIED; - } - - talloc_destroy(mem_ctx); - - return NT_STATUS_OK; -} - -/**************************************************************************** - Reply to a NT_TRANSACT_CREATE call (needs to process SD's). -****************************************************************************/ - -static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - pstring fname; - char *params = *ppparams; - char *data = *ppdata; - /* Breakout the oplock request bits so we can set the reply bits separately. */ - int oplock_request = 0; - int fmode=0,rmode=0; - SMB_OFF_T file_len = 0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp = NULL; - char *p = NULL; - BOOL extended_oplock_granted = False; - uint32 flags; - uint32 desired_access; - uint32 file_attributes; - uint32 share_access; - uint32 create_disposition; - uint32 create_options; - uint32 sd_len; - uint16 root_dir_fid; - SMB_BIG_UINT allocation_size = 0; - int smb_ofun; - int smb_open_mode; - time_t c_time; - NTSTATUS status; - - DEBUG(5,("call_nt_transact_create\n")); - - /* - * If it's an IPC, use the pipe handler. - */ - - if (IS_IPC(conn)) { - if (lp_nt_pipe_support()) - return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, - bufsize, - ppsetup, setup_count, - ppparams, parameter_count, - ppdata, data_count); - else - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* - * Ensure minimum number of parameters sent. - */ - - if(parameter_count < 54) { - DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)parameter_count)); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - flags = IVAL(params,0); - desired_access = IVAL(params,8); - file_attributes = IVAL(params,20); - share_access = IVAL(params,24); - create_disposition = IVAL(params,28); - create_options = IVAL(params,32); - sd_len = IVAL(params,36); - root_dir_fid = (uint16)IVAL(params,4); - - if (create_options & FILE_OPEN_BY_FILE_ID) { - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); - } - - /* - * We need to construct the open_and_X ofun value from the - * NT values, as that's what our code is structured to accept. - */ - - if((smb_ofun = map_create_disposition( create_disposition )) == -1) - return ERROR_DOS(ERRDOS,ERRbadmem); - - /* - * Get the file name. - */ - - if(root_dir_fid != 0) { - /* - * This filename is relative to a directory fid. - */ - - files_struct *dir_fsp = file_fsp(params,4); - size_t dir_name_len; - - if(!dir_fsp) - return ERROR_DOS(ERRDOS,ERRbadfid); - - if(!dir_fsp->is_directory) { - srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( strchr_m(fname, ':')) - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - - return ERROR_DOS(ERRDOS,ERRbadfid); - } - - /* - * Copy in the base directory name. - */ - - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); - - /* - * Ensure it ends in a '\'. - */ - - if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { - pstrcat(fname, "\\"); - dir_name_len++; - } - - { - pstring tmpname; - srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - pstrcat(fname, tmpname); - } - } else { - srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - /* - * Check to see if this is a mac fork of some kind. - */ - - if( strchr_m(fname, ':')) - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } - - /* - * Now contruct the smb_open_mode value from the desired access - * and the share access. - */ - - if((smb_open_mode = map_share_mode( fname, create_options, &desired_access, - share_access, file_attributes)) == -1) - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; - - /* - * Check if POSIX semantics are wanted. - */ - - set_posix_case_semantics(file_attributes); - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - /* - * If it's a request for a directory open, deal with it separately. - */ - - if(create_options & FILE_DIRECTORY_FILE) { - - /* Can't open a temp directory. IFS kit test. */ - if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - oplock_request = 0; - - /* - * We will get a create directory here if the Win32 - * app specified a security descriptor in the - * CreateDirectory() call. - */ - - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - - if(!fsp) { - restore_case_semantics(file_attributes); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - - } else { - - /* - * Ordinary file case. - */ - - fsp = open_file_shared1(conn,fname,&sbuf,desired_access, - smb_open_mode,smb_ofun,file_attributes, - oplock_request,&rmode,&smb_action); - - if (!fsp) { - - if(errno == EISDIR) { - - /* - * Fail the open if it was explicitly a non-directory file. - */ - - 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); - return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY); - } - - oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - - if(!fsp) { - restore_case_semantics(file_attributes); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - } else { - restore_case_semantics(file_attributes); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - } - - file_len = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) - fmode = FILE_ATTRIBUTE_NORMAL; - - if (fmode & aDIR) { - close_file(fsp,False); - restore_case_semantics(file_attributes); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - extended_oplock_granted = True; - - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - extended_oplock_granted = True; - } - - /* - * Now try and apply the desired SD. - */ - - if (sd_len && !NT_STATUS_IS_OK(status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) { - close_file(fsp,False); - restore_case_semantics(file_attributes); - return ERROR_NT(status); - } - - restore_case_semantics(file_attributes); - - /* Save the requested allocation size. */ - allocation_size = (SMB_BIG_UINT)IVAL(params,12); -#ifdef LARGE_SMB_OFF_T - allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32); -#endif - if (allocation_size && (allocation_size > file_len)) { - fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); - if (fsp->is_directory) { - close_file(fsp,False); - END_PROFILE(SMBntcreateX); - /* Can't set allocation size on a directory. */ - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,False); - return ERROR_NT(NT_STATUS_DISK_FULL); - } - } else { - fsp->initial_allocation_size = SMB_ROUNDUP(((SMB_BIG_UINT)file_len),SMB_ROUNDUP_ALLOCATION_SIZE); - } - - /* Realloc the size of parameters and data we will return */ - params = nttrans_realloc(ppparams, 69); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - p = params; - if (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); - else - SCVAL(p,0,NO_OPLOCK_RETURN); - - p += 2; - SSVAL(p,0,fsp->fnum); - p += 2; - if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN)) - SIVAL(p,0,FILE_WAS_SUPERSEDED); - else - SIVAL(p,0,smb_action); - p += 8; - - /* Create time. */ - c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); - - if (lp_dos_filetime_resolution(SNUM(conn))) { - c_time &= ~1; - sbuf.st_atime &= ~1; - sbuf.st_mtime &= ~1; - sbuf.st_mtime &= ~1; - } - - put_long_date(p,c_time); - p += 8; - put_long_date(p,sbuf.st_atime); /* access time */ - p += 8; - put_long_date(p,sbuf.st_mtime); /* write time */ - p += 8; - put_long_date(p,sbuf.st_mtime); /* change time */ - p += 8; - SIVAL(p,0,fmode); /* File Attributes. */ - p += 4; - SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); - p += 8; - SOFF_T(p,0,file_len); - p += 8; - if (flags & EXTENDED_RESPONSE_REQUIRED) - SSVAL(p,2,0x7); - p += 4; - SCVAL(p,0,fsp->is_directory ? 1 : 0); - - DEBUG(5,("call_nt_transact_create: open name = %s\n", fname)); - - /* Send the required number of replies */ - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); - - return -1; -} - -/**************************************************************************** - Reply to a NT CANCEL request. -****************************************************************************/ - -int reply_ntcancel(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - /* - * Go through and cancel any pending change notifies. - */ - - int mid = SVAL(inbuf,smb_mid); - START_PROFILE(SMBntcancel); - remove_pending_change_notify_requests_by_mid(mid); - remove_pending_lock_requests_by_mid(mid); - srv_cancel_sign_response(mid); - - DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", mid)); - - END_PROFILE(SMBntcancel); - return(-1); -} - -/**************************************************************************** - Reply to a NT rename request. -****************************************************************************/ - -int reply_ntrename(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - int outsize = 0; - pstring name; - pstring newname; - char *p; - NTSTATUS status; - uint16 attrs = SVAL(inbuf,smb_vwv0); - uint16 rename_type = SVAL(inbuf,smb_vwv1); - - START_PROFILE(SMBntrename); - - if ((rename_type != RENAME_FLAG_RENAME) && (rename_type != RENAME_FLAG_HARD_LINK)) { - END_PROFILE(SMBntrename); - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBntrename); - return ERROR_NT(status); - } - - if( strchr_m(name, ':')) { - /* Can't rename a stream. */ - END_PROFILE(SMBntrename); - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - - p++; - p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBntrename); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - - DEBUG(3,("reply_ntrename : %s -> %s\n",name,newname)); - - if (rename_type == RENAME_FLAG_RENAME) { - status = rename_internals(conn, name, newname, attrs, False); - } else { - status = hardlink_internals(conn, name, newname); - } - - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBntrename); - 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); - - END_PROFILE(SMBntrename); - return(outsize); -} - -/**************************************************************************** - Reply to an unsolicited SMBNTtranss - just ignore it! -****************************************************************************/ - -int reply_nttranss(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - START_PROFILE(SMBnttranss); - DEBUG(4,("Ignoring nttranss of length %d\n",length)); - END_PROFILE(SMBnttranss); - return(-1); -} - -/**************************************************************************** - Reply to a notify change - queue the request and - don't allow a directory to be opened. -****************************************************************************/ - -static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - char *setup = *ppsetup; - files_struct *fsp; - uint32 flags; - - if(setup_count < 6) - return ERROR_DOS(ERRDOS,ERRbadfunc); - - fsp = file_fsp(setup,4); - flags = IVAL(setup, 0); - - DEBUG(3,("call_nt_transact_notify_change\n")); - - if(!fsp) - return ERROR_DOS(ERRDOS,ERRbadfid); - - if((!fsp->is_directory) || (conn != fsp->conn)) - return ERROR_DOS(ERRDOS,ERRbadfid); - - if (!change_notify_set(inbuf, fsp, conn, flags)) - return(UNIXERROR(ERRDOS,ERRbadfid)); - - DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \ -name = %s\n", fsp->fsp_name )); - - return -1; -} - -/**************************************************************************** - Reply to an NT transact rename command. -****************************************************************************/ - -static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - char *params = *ppparams; - pstring new_name; - files_struct *fsp = NULL; - BOOL replace_if_exists = False; - NTSTATUS status; - - if(parameter_count < 4) - return ERROR_DOS(ERRDOS,ERRbadfunc); - - fsp = file_fsp(params, 0); - replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; - CHECK_FSP(fsp, conn); - srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - status = rename_internals(conn, fsp->fsp_name, - new_name, 0, replace_if_exists); - if (!NT_STATUS_IS_OK(status)) - return ERROR_NT(status); - - /* - * Rename was successful. - */ - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - - 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 - * update after a rename.. - */ - - process_pending_change_notify_queue((time_t)0); - - return -1; -} - -/****************************************************************************** - Fake up a completely empty SD. -*******************************************************************************/ - -static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) -{ - extern DOM_SID global_sid_World; - size_t sd_size; - - *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size); - if(!*ppsd) { - DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n")); - sd_size = 0; - } - - return sd_size; -} - -/**************************************************************************** - Reply to query a security descriptor. -****************************************************************************/ - -static int call_nt_transact_query_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); - char *params = *ppparams; - char *data = *ppdata; - prs_struct pd; - SEC_DESC *psd = NULL; - size_t sd_size; - uint32 security_info_wanted; - TALLOC_CTX *mem_ctx; - files_struct *fsp = NULL; - - if(parameter_count < 8) - return ERROR_DOS(ERRDOS,ERRbadfunc); - - fsp = file_fsp(params,0); - if(!fsp) - return ERROR_DOS(ERRDOS,ERRbadfid); - - security_info_wanted = IVAL(params,4); - - DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); - - params = nttrans_realloc(ppparams, 4); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - if ((mem_ctx = talloc_init("call_nt_transact_query_security_desc")) == NULL) { - DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - /* - * Get the permissions to return. - */ - - if (!lp_nt_acl_support(SNUM(conn))) - sd_size = get_null_nt_acl(mem_ctx, &psd); - else - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, security_info_wanted, &psd); - - if (sd_size == 0) { - talloc_destroy(mem_ctx); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size)); - - SIVAL(params,0,(uint32)sd_size); - - if(max_data_count < sd_size) { - - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL, - params, 4, *ppdata, 0); - talloc_destroy(mem_ctx); - return -1; - } - - /* - * Allocate the data we will point this at. - */ - - data = nttrans_realloc(ppdata, sd_size); - if(data == NULL) { - talloc_destroy(mem_ctx); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - /* - * Init the parse struct we will marshall into. - */ - - prs_init(&pd, 0, mem_ctx, MARSHALL); - - /* - * Setup the prs_struct to point at the memory we just - * allocated. - */ - - prs_give_memory( &pd, data, (uint32)sd_size, False); - - /* - * Finally, linearize into the outgoing buffer. - */ - - if(!sec_io_desc( "sd data", &psd, &pd, 1)) { - DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \ -security descriptor.\n")); - /* - * Return access denied for want of a better error message.. - */ - talloc_destroy(mem_ctx); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* - * Now we can delete the security descriptor. - */ - - talloc_destroy(mem_ctx); - - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size); - return -1; -} - -/**************************************************************************** - Reply to set a security descriptor. Map to UNIX perms or POSIX ACLs. -****************************************************************************/ - -static int call_nt_transact_set_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - char *params= *ppparams; - char *data = *ppdata; - files_struct *fsp = NULL; - uint32 security_info_sent = 0; - NTSTATUS nt_status; - - if(parameter_count < 8) - return ERROR_DOS(ERRDOS,ERRbadfunc); - - if((fsp = file_fsp(params,0)) == NULL) - return ERROR_DOS(ERRDOS,ERRbadfid); - - if(!lp_nt_acl_support(SNUM(conn))) - goto done; - - security_info_sent = IVAL(params,4); - - DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name, - (unsigned int)security_info_sent )); - - if (data_count == 0) - return ERROR_DOS(ERRDOS, ERRnoaccess); - - if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent))) - return ERROR_NT(nt_status); - - done: - - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - return -1; -} - -/**************************************************************************** - Reply to NT IOCTL -****************************************************************************/ - -static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - uint32 function; - uint16 fidnum; - files_struct *fsp; - uint8 isFSctl; - uint8 compfilter; - static BOOL logged_message; - char *pdata = *ppdata; - - if (setup_count != 8) { - DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count)); - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); - } - - function = IVAL(*ppsetup, 0); - fidnum = SVAL(*ppsetup, 4); - isFSctl = CVAL(*ppsetup, 6); - compfilter = CVAL(*ppsetup, 7); - - DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", - function, fidnum, isFSctl, compfilter)); - - fsp=file_fsp(*ppsetup, 4); - /* this check is done in each implemented function case for now - because I don't want to break anything... --metze - FSP_BELONGS_CONN(fsp,conn);*/ - - switch (function) { - case FSCTL_SET_SPARSE: - /* pretend this succeeded - tho strictly we should - mark the file sparse (if the local fs supports it) - so we can know if we need to pre-allocate or not */ - - DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum)); - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - return -1; - - case FSCTL_0x000900C0: - /* pretend this succeeded - don't know what this really is - but works ok like this --metze - */ - - DEBUG(10,("FSCTL_0x000900C0: called on FID[0x%04X](but not implemented)\n",fidnum)); - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - return -1; - - case FSCTL_GET_REPARSE_POINT: - /* pretend this fail - my winXP does it like this - * --metze - */ - - DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); - return -1; - - case FSCTL_SET_REPARSE_POINT: - /* pretend this fail - I'm assuming this because of the FSCTL_GET_REPARSE_POINT case. - * --metze - */ - - DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); - return -1; - - case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/ - { - /* - * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots) - * and return their volume names. If max_data_count is 16, then it is just - * asking for the number of volumes and length of the combined names. - * - * pdata is the data allocated by our caller, but that uses - * total_data_count (which is 0 in our case) rather than max_data_count. - * Allocate the correct amount and return the pointer to let - * it be deallocated when we return. - */ - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); - SHADOW_COPY_DATA *shadow_data = NULL; - TALLOC_CTX *shadow_mem_ctx = NULL; - BOOL labels = False; - uint32 labels_data_count = 0; - uint32 i; - char *cur_pdata; - - FSP_BELONGS_CONN(fsp,conn); - - if (max_data_count < 16) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", - max_data_count)); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - if (max_data_count > 16) { - labels = True; - } - - shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA"); - if (shadow_mem_ctx == NULL) { - DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n")); - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - - shadow_data = (SHADOW_COPY_DATA *)talloc_zero(shadow_mem_ctx,sizeof(SHADOW_COPY_DATA)); - if (shadow_data == NULL) { - DEBUG(0,("talloc_zero() failed!\n")); - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - - shadow_data->mem_ctx = shadow_mem_ctx; - - /* - * Call the VFS routine to actually do the work. - */ - if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { - talloc_destroy(shadow_data->mem_ctx); - if (errno == ENOSYS) { - DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", - conn->connectpath)); - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); - } else { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", - conn->connectpath)); - return ERROR_NT(NT_STATUS_UNSUCCESSFUL); - } - } - - labels_data_count = (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL))+2; - - if (!labels) { - data_count = 16; - } else { - data_count = 12+labels_data_count+4; - } - - if (max_data_count<data_count) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n", - max_data_count,data_count)); - talloc_destroy(shadow_data->mem_ctx); - return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL); - } - - pdata = nttrans_realloc(ppdata, data_count); - if (pdata == NULL) { - talloc_destroy(shadow_data->mem_ctx); - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - - cur_pdata = pdata; - - /* num_volumes 4 bytes */ - SIVAL(pdata,0,shadow_data->num_volumes); - - if (labels) { - /* num_labels 4 bytes */ - SIVAL(pdata,4,shadow_data->num_volumes); - } - - /* needed_data_count 4 bytes */ - SIVAL(pdata,8,labels_data_count); - - cur_pdata+=12; - - DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", - shadow_data->num_volumes,fsp->fsp_name)); - if (labels && shadow_data->labels) { - for (i=0;i<shadow_data->num_volumes;i++) { - srvstr_push(outbuf, cur_pdata, shadow_data->labels[i], 2*sizeof(SHADOW_COPY_LABEL), STR_UNICODE|STR_TERMINATE); - cur_pdata+=2*sizeof(SHADOW_COPY_LABEL); - DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i])); - } - } - - talloc_destroy(shadow_data->mem_ctx); - - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, pdata, data_count); - - return -1; - } - - case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ - { - /* pretend this succeeded - - * - * we have to send back a list with all files owned by this SID - * - * but I have to check that --metze - */ - DOM_SID sid; - uid_t uid; - size_t sid_len = MIN(data_count-4,SID_MAX_SIZE); - - DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); - - FSP_BELONGS_CONN(fsp,conn); - - /* unknown 4 bytes: this is not the length of the sid :-( */ - /*unknown = IVAL(pdata,0);*/ - - sid_parse(pdata+4,sid_len,&sid); - DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid))); - - if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &uid))) { - DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", - sid_string_static(&sid),(unsigned long)sid_len)); - uid = (-1); - } - - /* we can take a look at the find source :-) - * - * find ./ -uid $uid -name '*' is what we need here - * - * - * and send 4bytes len and then NULL terminated unicode strings - * for each file - * - * but I don't know how to deal with the paged results - * (maybe we can hang the result anywhere in the fsp struct) - * - * we don't send all files at once - * and at the next we should *not* start from the beginning, - * so we have to cache the result - * - * --metze - */ - - /* this works for now... */ - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); - return -1; - } - default: - if (!logged_message) { - logged_message = True; /* Only print this once... */ - DEBUG(0,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", - function)); - } - } - - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); -} - - -#ifdef HAVE_SYS_QUOTAS -/**************************************************************************** - Reply to get user quota -****************************************************************************/ - -static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - NTSTATUS nt_status = NT_STATUS_OK; - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); - char *params = *ppparams; - char *pdata = *ppdata; - char *entry; - int data_len=0,param_len=0; - int qt_len=0; - int entry_len = 0; - files_struct *fsp = NULL; - uint16 level = 0; - size_t sid_len; - DOM_SID sid; - BOOL start_enum = True; - SMB_NTQUOTA_STRUCT qt; - SMB_NTQUOTA_LIST *tmp_list; - SMB_NTQUOTA_HANDLE *qt_handle = NULL; - extern struct current_user current_user; - - ZERO_STRUCT(qt); - - /* access check */ - if (current_user.uid != 0) { - DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n", - lp_servicename(SNUM(conn)),conn->user)); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* - * Ensure minimum number of parameters sent. - */ - - if (parameter_count < 4) { - DEBUG(0,("TRANSACT_GET_USER_QUOTA: requires %d >= 4 bytes parameters\n",parameter_count)); - return ERROR_DOS(ERRDOS,ERRinvalidparam); - } - - /* maybe we can check the quota_fnum */ - fsp = file_fsp(params,0); - if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { - DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); - return ERROR_NT(NT_STATUS_INVALID_HANDLE); - } - - /* the NULL pointer cheking for fsp->fake_file_handle->pd - * is done by CHECK_NTQUOTA_HANDLE_OK() - */ - qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->pd; - - level = SVAL(params,2); - - /* unknown 12 bytes leading in params */ - - switch (level) { - case TRANSACT_GET_USER_QUOTA_LIST_CONTINUE: - /* seems that we should continue with the enum here --metze */ - - if (qt_handle->quota_list!=NULL && - qt_handle->tmp_list==NULL) { - - /* free the list */ - free_ntquota_list(&(qt_handle->quota_list)); - - /* Realloc the size of parameters and data we will return */ - param_len = 4; - params = nttrans_realloc(ppparams, param_len); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - data_len = 0; - SIVAL(params,0,data_len); - - break; - } - - start_enum = False; - - case TRANSACT_GET_USER_QUOTA_LIST_START: - - if (qt_handle->quota_list==NULL && - qt_handle->tmp_list==NULL) { - start_enum = True; - } - - if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) - return ERROR_DOS(ERRSRV,ERRerror); - - /* Realloc the size of parameters and data we will return */ - param_len = 4; - params = nttrans_realloc(ppparams, param_len); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - /* we should not trust the value in max_data_count*/ - max_data_count = MIN(max_data_count,2048); - - pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/ - if(pdata == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - entry = pdata; - - - /* set params Size of returned Quota Data 4 bytes*/ - /* but set it later when we know it */ - - /* for each entry push the data */ - - if (start_enum) { - qt_handle->tmp_list = qt_handle->quota_list; - } - - tmp_list = qt_handle->tmp_list; - - for (;((tmp_list!=NULL)&&((qt_len +40+SID_MAX_SIZE)<max_data_count)); - tmp_list=tmp_list->next,entry+=entry_len,qt_len+=entry_len) { - - sid_len = sid_size(&tmp_list->quotas->sid); - entry_len = 40 + sid_len; - - /* nextoffset entry 4 bytes */ - SIVAL(entry,0,entry_len); - - /* then the len of the SID 4 bytes */ - SIVAL(entry,4,sid_len); - - /* unknown data 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-metze*/ - - /* the used disk space 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,16,tmp_list->quotas->usedspace); - - /* the soft quotas 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,24,tmp_list->quotas->softlim); - - /* the hard quotas 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,32,tmp_list->quotas->hardlim); - - /* and now the SID */ - sid_linearize(entry+40, sid_len, &tmp_list->quotas->sid); - } - - qt_handle->tmp_list = tmp_list; - - /* overwrite the offset of the last entry */ - SIVAL(entry-entry_len,0,0); - - data_len = 4+qt_len; - /* overwrite the params quota_data_len */ - SIVAL(params,0,data_len); - - break; - - case TRANSACT_GET_USER_QUOTA_FOR_SID: - - /* unknown 4 bytes IVAL(pdata,0) */ - - if (data_count < 8) { - DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8)); - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - sid_len = IVAL(pdata,4); - - if (data_count < 8+sid_len) { - DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %lu bytes data\n",data_count,(unsigned long)(8+sid_len))); - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - data_len = 4+40+sid_len; - - if (max_data_count < data_len) { - DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: max_data_count(%d) < data_len(%d)\n", - max_data_count, data_len)); - param_len = 4; - SIVAL(params,0,data_len); - data_len = 0; - nt_status = NT_STATUS_BUFFER_TOO_SMALL; - break; - } - - sid_parse(pdata+8,sid_len,&sid); - - - if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { - ZERO_STRUCT(qt); - /* - * we have to return zero's in all fields - * instead of returning an error here - * --metze - */ - } - - /* Realloc the size of parameters and data we will return */ - param_len = 4; - params = nttrans_realloc(ppparams, param_len); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - pdata = nttrans_realloc(ppdata, data_len); - if(pdata == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); - - entry = pdata; - - /* set params Size of returned Quota Data 4 bytes*/ - SIVAL(params,0,data_len); - - /* nextoffset entry 4 bytes */ - SIVAL(entry,0,0); - - /* then the len of the SID 4 bytes */ - SIVAL(entry,4,sid_len); - - /* unknown data 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-mezte*/ - - /* the used disk space 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,16,qt.usedspace); - - /* the soft quotas 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,24,qt.softlim); - - /* the hard quotas 8 bytes SMB_BIG_UINT */ - SBIG_UINT(entry,32,qt.hardlim); - - /* and now the SID */ - sid_linearize(entry+40, sid_len, &sid); - - break; - - default: - DEBUG(0,("do_nt_transact_get_user_quota: fnum %d unknown level 0x%04hX\n",fsp->fnum,level)); - return ERROR_DOS(ERRSRV,ERRerror); - break; - } - - send_nt_replies(inbuf, outbuf, bufsize, nt_status, params, param_len, pdata, data_len); - - return -1; -} - -/**************************************************************************** - Reply to set user quota -****************************************************************************/ - -static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **ppsetup, uint32 setup_count, - char **ppparams, uint32 parameter_count, - char **ppdata, uint32 data_count) -{ - char *params = *ppparams; - char *pdata = *ppdata; - int data_len=0,param_len=0; - SMB_NTQUOTA_STRUCT qt; - size_t sid_len; - DOM_SID sid; - files_struct *fsp = NULL; - - ZERO_STRUCT(qt); - - /* access check */ - if (conn->admin_user != True) { - DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n", - lp_servicename(SNUM(conn)),conn->user)); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* - * Ensure minimum number of parameters sent. - */ - - if (parameter_count < 2) { - DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= 2 bytes parameters\n",parameter_count)); - return ERROR_DOS(ERRDOS,ERRinvalidparam); - } - - /* maybe we can check the quota_fnum */ - fsp = file_fsp(params,0); - if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { - DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); - return ERROR_NT(NT_STATUS_INVALID_HANDLE); - } - - if (data_count < 40) { - DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40)); - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - /* offset to next quota record. - * 4 bytes IVAL(pdata,0) - * unused here... - */ - - /* sid len */ - sid_len = IVAL(pdata,4); - - if (data_count < 40+sid_len) { - DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %lu bytes data\n",data_count,(unsigned long)40+sid_len)); - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - /* unknown 8 bytes in pdata - * maybe its the change time in NTTIME - */ - - /* the used space 8 bytes (SMB_BIG_UINT)*/ - qt.usedspace = (SMB_BIG_UINT)IVAL(pdata,16); -#ifdef LARGE_SMB_OFF_T - qt.usedspace |= (((SMB_BIG_UINT)IVAL(pdata,20)) << 32); -#else /* LARGE_SMB_OFF_T */ - if ((IVAL(pdata,20) != 0)&& - ((qt.usedspace != 0xFFFFFFFF)|| - (IVAL(pdata,20)!=0xFFFFFFFF))) { - /* more than 32 bits? */ - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } -#endif /* LARGE_SMB_OFF_T */ - - /* the soft quotas 8 bytes (SMB_BIG_UINT)*/ - qt.softlim = (SMB_BIG_UINT)IVAL(pdata,24); -#ifdef LARGE_SMB_OFF_T - qt.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32); -#else /* LARGE_SMB_OFF_T */ - if ((IVAL(pdata,28) != 0)&& - ((qt.softlim != 0xFFFFFFFF)|| - (IVAL(pdata,28)!=0xFFFFFFFF))) { - /* more than 32 bits? */ - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } -#endif /* LARGE_SMB_OFF_T */ - - /* the hard quotas 8 bytes (SMB_BIG_UINT)*/ - qt.hardlim = (SMB_BIG_UINT)IVAL(pdata,32); -#ifdef LARGE_SMB_OFF_T - qt.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32); -#else /* LARGE_SMB_OFF_T */ - if ((IVAL(pdata,36) != 0)&& - ((qt.hardlim != 0xFFFFFFFF)|| - (IVAL(pdata,36)!=0xFFFFFFFF))) { - /* more than 32 bits? */ - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } -#endif /* LARGE_SMB_OFF_T */ - - sid_parse(pdata+40,sid_len,&sid); - DEBUGADD(8,("SID: %s\n",sid_string_static(&sid))); - - /* 44 unknown bytes left... */ - - if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { - return ERROR_DOS(ERRSRV,ERRerror); - } - - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, param_len, pdata, data_len); - - return -1; -} -#endif /* HAVE_SYS_QUOTAS */ - -/**************************************************************************** - Reply to a SMBNTtrans. -****************************************************************************/ - -int reply_nttrans(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - int outsize = 0; -#if 0 /* Not used. */ - uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount); - uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount); - uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); -#endif /* Not used. */ - uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount); - uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount); - uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount); - uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset); - uint32 data_count = IVAL(inbuf,smb_nt_DataCount); - uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset); - uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */ - uint16 function_code = SVAL( inbuf, smb_nt_Function); - char *params = NULL, *data = NULL, *setup = NULL; - uint32 num_params_sofar, num_data_sofar; - START_PROFILE(SMBnttrans); - - if(global_oplock_break && - ((function_code == NT_TRANSACT_CREATE) || - (function_code == NT_TRANSACT_RENAME))) { - /* - * Queue this open message as we are the process of an oplock break. - */ - - DEBUG(2,("reply_nttrans: queueing message code 0x%x \ -due to being in oplock break state.\n", (unsigned int)function_code )); - - push_oplock_pending_smb_message( inbuf, length); - END_PROFILE(SMBnttrans); - return -1; - } - - if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRaccess); - } - - outsize = set_message(outbuf,0,0,True); - - /* - * All nttrans messages we handle have smb_wct == 19 + setup_count. - * Ensure this is so as a sanity check. - */ - - if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) { - DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", - CVAL(inbuf, smb_wct), 19 + (setup_count/2))); - goto bad_param; - } - - /* Allocate the space for the setup, the maximum needed parameters and data */ - - if(setup_count > 0) - setup = (char *)malloc(setup_count); - if (total_parameter_count > 0) - params = (char *)malloc(total_parameter_count); - if (total_data_count > 0) - data = (char *)malloc(total_data_count); - - if ((total_parameter_count && !params) || (total_data_count && !data) || - (setup_count && !setup)) { - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); - DEBUG(0,("reply_nttrans : Out of memory\n")); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - /* Copy the param and data bytes sent with this request into the params buffer */ - num_params_sofar = parameter_count; - num_data_sofar = data_count; - - if (parameter_count > total_parameter_count || data_count > total_data_count) - goto bad_param; - - if(setup) { - DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); - if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) || - (smb_nt_SetupStart + setup_count < setup_count)) - goto bad_param; - if (smb_nt_SetupStart + setup_count > length) - goto bad_param; - - memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); - dump_data(10, setup, setup_count); - } - if(params) { - DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); - if ((parameter_offset + parameter_count < parameter_offset) || - (parameter_offset + parameter_count < parameter_count)) - goto bad_param; - if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)|| - (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) - goto bad_param; - - memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); - dump_data(10, params, parameter_count); - } - if(data) { - DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); - if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) - goto bad_param; - if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) || - (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) - goto bad_param; - - memcpy( data, smb_base(inbuf) + data_offset, data_count); - dump_data(10, data, data_count); - } - - srv_signing_trans_start(SVAL(inbuf,smb_mid)); - - if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - srv_signing_trans_stop(); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_nttrans: send_smb failed."); - - while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { - BOOL ret; - uint32 parameter_displacement; - uint32 data_displacement; - - ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); - - /* - * The sequence number for the trans reply is always - * based on the last secondary received. - */ - - srv_signing_trans_start(SVAL(inbuf,smb_mid)); - - if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) { - outsize = set_message(outbuf,0,0,True); - if(ret) { - DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); - } else { - DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", - (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - } - goto bad_param; - } - - /* Revise total_params and total_data in case they have changed downwards */ - if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count) - total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); - if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count) - total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); - - parameter_count = IVAL(inbuf,smb_nts_ParameterCount); - parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset); - parameter_displacement = IVAL(inbuf, smb_nts_ParameterDisplacement); - num_params_sofar += parameter_count; - - data_count = IVAL(inbuf, smb_nts_DataCount); - data_displacement = IVAL(inbuf, smb_nts_DataDisplacement); - data_offset = IVAL(inbuf, smb_nts_DataOffset); - num_data_sofar += data_count; - - if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) { - DEBUG(0,("reply_nttrans2: data overflow in secondary nttrans packet")); - goto bad_param; - } - - if (parameter_count) { - if (parameter_displacement + parameter_count >= total_parameter_count) - goto bad_param; - if ((parameter_displacement + parameter_count < parameter_displacement) || - (parameter_displacement + parameter_count < parameter_count)) - goto bad_param; - if (parameter_displacement > total_parameter_count) - goto bad_param; - if ((smb_base(inbuf) + parameter_offset + parameter_count >= inbuf + bufsize) || - (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) - goto bad_param; - if (parameter_displacement + params < params) - goto bad_param; - - memcpy( ¶ms[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count); - } - - if (data_count) { - if (data_displacement + data_count >= total_data_count) - goto bad_param; - if ((data_displacement + data_count < data_displacement) || - (data_displacement + data_count < data_count)) - goto bad_param; - if (data_displacement > total_data_count) - goto bad_param; - if ((smb_base(inbuf) + data_offset + data_count >= inbuf + bufsize) || - (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) - goto bad_param; - if (data_displacement + data < data) - goto bad_param; - - memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count); - } - } - } - - if (Protocol >= PROTOCOL_NT1) - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME); - - /* Now we must call the relevant NT_TRANS function */ - switch(function_code) { - case NT_TRANSACT_CREATE: - START_PROFILE_NESTED(NT_transact_create); - outsize = call_nt_transact_create(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_create); - break; - case NT_TRANSACT_IOCTL: - START_PROFILE_NESTED(NT_transact_ioctl); - outsize = call_nt_transact_ioctl(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_ioctl); - break; - case NT_TRANSACT_SET_SECURITY_DESC: - START_PROFILE_NESTED(NT_transact_set_security_desc); - outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_set_security_desc); - break; - case NT_TRANSACT_NOTIFY_CHANGE: - START_PROFILE_NESTED(NT_transact_notify_change); - outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_notify_change); - break; - case NT_TRANSACT_RENAME: - START_PROFILE_NESTED(NT_transact_rename); - outsize = call_nt_transact_rename(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_rename); - break; - - case NT_TRANSACT_QUERY_SECURITY_DESC: - START_PROFILE_NESTED(NT_transact_query_security_desc); - outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_query_security_desc); - break; -#ifdef HAVE_SYS_QUOTAS - case NT_TRANSACT_GET_USER_QUOTA: - START_PROFILE_NESTED(NT_transact_get_user_quota); - outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_get_user_quota); - break; - case NT_TRANSACT_SET_USER_QUOTA: - START_PROFILE_NESTED(NT_transact_set_user_quota); - outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf, - length, bufsize, - &setup, setup_count, - ¶ms, total_parameter_count, - &data, total_data_count); - END_PROFILE_NESTED(NT_transact_set_user_quota); - break; -#endif /* HAVE_SYS_QUOTAS */ - default: - /* Error in request */ - DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); - SAFE_FREE(setup); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBnttrans); - srv_signing_trans_stop(); - return ERROR_DOS(ERRSRV,ERRerror); - } - - /* As we do not know how many data packets will need to be - returned here the various call_nt_transact_xxxx calls - must send their own. Thus a call_nt_transact_xxxx routine only - returns a value other than -1 when it wants to send - an error packet. - */ - - srv_signing_trans_stop(); - - 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 - returning an error packet. */ - - bad_param: - - srv_signing_trans_stop(); - SAFE_FREE(params); - SAFE_FREE(data); - SAFE_FREE(setup); - END_PROFILE(SMBnttrans); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); -} diff --git a/source/smbd/open.c b/source/smbd/open.c deleted file mode 100644 index 8ab5dab6ac9..00000000000 --- a/source/smbd/open.c +++ /dev/null @@ -1,1462 +0,0 @@ -/* - Unix SMB/CIFS implementation. - file opening and share modes - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Jeremy Allison 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern userdom_struct current_user_info; -extern uint16 global_oplock_port; -extern uint16 global_smbpid; -extern BOOL global_client_failed_oplock_break; - -/**************************************************************************** - fd support routines - attempt to do a dos_open. -****************************************************************************/ - -static int fd_open(struct connection_struct *conn, const char *fname, - int flags, mode_t mode) -{ - int fd; -#ifdef O_NOFOLLOW - if (!lp_symlinks(SNUM(conn))) - flags |= O_NOFOLLOW; -#endif - - fd = SMB_VFS_OPEN(conn,fname,flags,mode); - - DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", fname, - flags, (int)mode, fd, (fd == -1) ? strerror(errno) : "" )); - - return fd; -} - -/**************************************************************************** - Close the file associated with a fsp. -****************************************************************************/ - -int fd_close(struct connection_struct *conn, files_struct *fsp) -{ - if (fsp->fd == -1) - return 0; /* what we used to call a stat open. */ - return fd_close_posix(conn, fsp); -} - - -/**************************************************************************** - Check a filename for the pipe string. -****************************************************************************/ - -static void check_for_pipe(const char *fname) -{ - /* special case of pipe opens */ - char s[10]; - StrnCpy(s,fname,sizeof(s)-1); - strlower_m(s); - if (strstr(s,"pipe/")) { - DEBUG(3,("Rejecting named pipe open for %s\n",fname)); - unix_ERR_class = ERRSRV; - unix_ERR_code = ERRaccess; - unix_ERR_ntstatus = NT_STATUS_ACCESS_DENIED; - } -} - -/**************************************************************************** - Open a file. -****************************************************************************/ - -static BOOL open_file(files_struct *fsp,connection_struct *conn, - const char *fname,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode, uint32 desired_access) -{ - extern struct current_user current_user; - int accmode = (flags & O_ACCMODE); - int local_flags = flags; - - fsp->fd = -1; - fsp->oplock_type = NO_OPLOCK; - errno = EPERM; - - /* Check permissions */ - - /* - * This code was changed after seeing a client open request - * containing the open mode of (DENY_WRITE/read-only) with - * the 'create if not exist' bit set. The previous code - * would fail to open the file read only on a read-only share - * as it was checking the flags parameter directly against O_RDONLY, - * this was failing as the flags parameter was set to O_RDONLY|O_CREAT. - * JRA. - */ - - if (!CAN_WRITE(conn)) { - /* It's a read-only share - fail if we wanted to write. */ - if(accmode != O_RDONLY) { - DEBUG(3,("Permission denied opening %s\n",fname)); - check_for_pipe(fname); - return False; - } else if(flags & O_CREAT) { - /* We don't want to write - but we must make sure that O_CREAT - doesn't create the file if we have write access into the - directory. - */ - flags &= ~O_CREAT; - local_flags &= ~O_CREAT; - } - } - - /* - * This little piece of insanity is inspired by the - * fact that an NT client can open a file for O_RDONLY, - * but set the create disposition to FILE_EXISTS_TRUNCATE. - * If the client *can* write to the file, then it expects to - * truncate the file, even though it is opening for readonly. - * Quicken uses this stupid trick in backup file creation... - * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net> - * for helping track this one down. It didn't bite us in 2.0.x - * as we always opened files read-write in that release. JRA. - */ - - if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { - DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname )); - local_flags = (flags & ~O_ACCMODE)|O_RDWR; - } - - if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - (local_flags & O_CREAT) || ((local_flags & O_TRUNC) == O_TRUNC) ) { - - /* - * We can't actually truncate here as the file may be locked. - * open_file_shared will take care of the truncate later. JRA. - */ - - local_flags &= ~O_TRUNC; - -#if defined(O_NONBLOCK) && defined(S_ISFIFO) - /* - * We would block on opening a FIFO with no one else on the - * other end. Do what we used to do and add O_NONBLOCK to the - * open flags. JRA. - */ - - if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode)) - local_flags |= O_NONBLOCK; -#endif - - /* Don't create files with Microsoft wildcard characters. */ - if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf) && ms_has_wild(fname)) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRinvalidname; - unix_ERR_ntstatus = NT_STATUS_OBJECT_NAME_INVALID; - return False; - } - - /* Actually do the open */ - fsp->fd = fd_open(conn, fname, local_flags, mode); - if (fsp->fd == -1) { - DEBUG(3,("Error opening file %s (%s) (local_flags=%d) (flags=%d)\n", - fname,strerror(errno),local_flags,flags)); - check_for_pipe(fname); - return False; - } - - /* Inherit the ACL if the file was created. */ - if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf)) - inherit_access_acl(conn, fname, mode); - - } else - fsp->fd = -1; /* What we used to call a stat open. */ - - if (!VALID_STAT(*psbuf)) { - int ret; - - if (fsp->fd == -1) - ret = SMB_VFS_STAT(conn, fname, psbuf); - else { - ret = SMB_VFS_FSTAT(fsp,fsp->fd,psbuf); - /* If we have an fd, this stat should succeed. */ - if (ret == -1) - DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) )); - } - - /* For a non-io open, this stat failing means file not found. JRA */ - if (ret == -1) { - fd_close(conn, fsp); - return False; - } - } - - /* - * POSIX allows read-only opens of directories. We don't - * want to do this (we use a different code path for this) - * so catch a directory open and return an EISDIR. JRA. - */ - - if(S_ISDIR(psbuf->st_mode)) { - fd_close(conn, fsp); - errno = EISDIR; - return False; - } - - fsp->mode = psbuf->st_mode; - fsp->inode = psbuf->st_ino; - fsp->dev = psbuf->st_dev; - fsp->vuid = current_user.vuid; - fsp->file_pid = global_smbpid; - fsp->size = psbuf->st_size; - fsp->can_lock = True; - fsp->can_read = ((flags & O_WRONLY)==0); - fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); - fsp->share_mode = 0; - fsp->desired_access = desired_access; - fsp->print_file = False; - fsp->modified = False; - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = False; - fsp->is_stat = False; - fsp->directory_delete_on_close = False; - string_set(&fsp->fsp_name,fname); - fsp->wcp = NULL; /* Write cache pointer. */ - - DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", - *current_user_info.smb_name ? current_user_info.smb_name : conn->user,fsp->fsp_name, - BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), - conn->num_files_open + 1)); - - return True; -} - -/**************************************************************************** - C. Hoch 11/22/95 - Helper for open_file_shared. - Truncate a file after checking locking; close file if locked. - **************************************************************************/ - -static int truncate_unless_locked(struct connection_struct *conn, files_struct *fsp) -{ - SMB_BIG_UINT mask = (SMB_BIG_UINT)-1; - - if (is_locked(fsp,fsp->conn,mask,0,WRITE_LOCK,True)){ - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRlock; - unix_ERR_ntstatus = dos_to_ntstatus(ERRDOS, ERRlock); - return -1; - } else { - return SMB_VFS_FTRUNCATE(fsp,fsp->fd,0); - } -} - -/******************************************************************* -return True if the filename is one of the special executable types -********************************************************************/ -static BOOL is_executable(const char *fname) -{ - if ((fname = strrchr_m(fname,'.'))) { - if (strequal(fname,".com") || - strequal(fname,".dll") || - strequal(fname,".exe") || - strequal(fname,".sym")) { - return True; - } - } - return False; -} - -enum {AFAIL,AREAD,AWRITE,AALL}; - -/******************************************************************* -reproduce the share mode access table -this is horrendoously complex, and really can't be justified on any -rational grounds except that this is _exactly_ what NT does. See -the DENY1 and DENY2 tests in smbtorture for a comprehensive set of -test routines. -********************************************************************/ -static int access_table(int new_deny,int old_deny,int old_mode, - BOOL same_pid, BOOL isexe) -{ - if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL); - - if (same_pid) { - if (isexe && old_mode == DOS_OPEN_RDONLY && - old_deny == DENY_DOS && new_deny == DENY_READ) { - return AFAIL; - } - if (!isexe && old_mode == DOS_OPEN_RDONLY && - old_deny == DENY_DOS && new_deny == DENY_DOS) { - return AREAD; - } - if (new_deny == DENY_FCB && old_deny == DENY_DOS) { - if (isexe) return AFAIL; - if (old_mode == DOS_OPEN_RDONLY) return AFAIL; - return AALL; - } - if (old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS) { - if (new_deny == DENY_FCB || new_deny == DENY_READ) { - if (isexe) return AREAD; - return AFAIL; - } - } - if (old_deny == DENY_FCB) { - if (new_deny == DENY_DOS || new_deny == DENY_FCB) return AALL; - return AFAIL; - } - } - - if (old_deny == DENY_DOS || new_deny == DENY_DOS || - old_deny == DENY_FCB || new_deny == DENY_FCB) { - if (isexe) { - if (old_deny == DENY_FCB || new_deny == DENY_FCB) { - return AFAIL; - } - if (old_deny == DENY_DOS) { - if (new_deny == DENY_READ && - (old_mode == DOS_OPEN_RDONLY || - old_mode == DOS_OPEN_RDWR)) { - return AFAIL; - } - if (new_deny == DENY_WRITE && - (old_mode == DOS_OPEN_WRONLY || - old_mode == DOS_OPEN_RDWR)) { - return AFAIL; - } - return AALL; - } - if (old_deny == DENY_NONE) return AALL; - if (old_deny == DENY_READ) return AWRITE; - if (old_deny == DENY_WRITE) return AREAD; - } - /* it isn't a exe, dll, sym or com file */ - if (old_deny == new_deny && same_pid) - return(AALL); - - if (old_deny == DENY_READ || new_deny == DENY_READ) return AFAIL; - if (old_mode == DOS_OPEN_RDONLY) return(AREAD); - - return(AFAIL); - } - - switch (new_deny) - { - case DENY_WRITE: - if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_RDONLY) return(AREAD); - if (old_deny==DENY_READ && old_mode==DOS_OPEN_RDONLY) return(AWRITE); - if (old_deny==DENY_NONE && old_mode==DOS_OPEN_RDONLY) return(AALL); - return(AFAIL); - case DENY_READ: - if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_WRONLY) return(AREAD); - if (old_deny==DENY_READ && old_mode==DOS_OPEN_WRONLY) return(AWRITE); - if (old_deny==DENY_NONE && old_mode==DOS_OPEN_WRONLY) return(AALL); - return(AFAIL); - case DENY_NONE: - if (old_deny==DENY_WRITE) return(AREAD); - if (old_deny==DENY_READ) return(AWRITE); - if (old_deny==DENY_NONE) return(AALL); - return(AFAIL); - } - return(AFAIL); -} - - -/**************************************************************************** -check if we can open a file with a share mode -****************************************************************************/ - -static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access, - const char *fname, BOOL fcbopen, int *flags) -{ - int deny_mode = GET_DENY_MODE(share_mode); - int old_open_mode = GET_OPEN_MODE(share->share_mode); - int old_deny_mode = GET_DENY_MODE(share->share_mode); - - /* - * 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. - */ - - if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n", - fname )); - /* Use errno to map to correct error. */ - unix_ERR_class = SMB_SUCCESS; - unix_ERR_code = 0; - unix_ERR_ntstatus = NT_STATUS_OK; - return False; - } - - /* this is a nasty hack, but necessary until we rewrite our open - handling to use a NTCreateX call as the basic call. - NT may open a file with neither read nor write access, and in - this case it expects the open not to conflict with any - existing deny modes. This happens (for example) during a - "xcopy /o" where the second file descriptor is used for - ACL sets - (tridge) - */ - - /* - * This is a bit wierd - the test for desired access not having the - * critical bits seems seems odd. Firstly, if both opens have no - * critical bits then always ignore. Then check the "allow delete" - * then check for either. This probably isn't quite right yet but - * gets us much closer. JRA. - */ - - /* - * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE - * and the existing desired_acces then share modes don't conflict. - */ - - if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) && - !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { - - /* - * Wrinkle discovered by smbtorture.... - * If both are non-io open and requester is asking for delete and current open has delete access - * but neither open has allowed file share delete then deny.... this is very strange and - * seems to be the only case in which non-io opens conflict. JRA. - */ - - if ((desired_access & DELETE_ACCESS) && (share->desired_access & DELETE_ACCESS) && - (!GET_ALLOW_SHARE_DELETE(share->share_mode) || !GET_ALLOW_SHARE_DELETE(share_mode))) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete access requests conflict.\n", - fname )); - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; - - return False; - } - - DEBUG(5,("check_share_mode: Allowing open on file %s as both desired access (0x%x) \ -and existing desired access (0x%x) are non-data opens\n", - fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); - return True; - } - - /* - * If delete access was requested and the existing share mode doesn't have - * ALLOW_SHARE_DELETE then deny. - */ - - if ((desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n", - fname )); - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; - - return False; - } - - /* - * The inverse of the above. - * If delete access was granted and the new share mode doesn't have - * ALLOW_SHARE_DELETE then deny. - */ - - if ((share->desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share_mode)) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n", - fname )); - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; - - return False; - } - - /* - * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE - * then share modes don't conflict. Likewise with existing desired access. - */ - - if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { - DEBUG(5,("check_share_mode: Allowing open on file %s as desired access (0x%x) doesn't conflict with\ -existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); - return True; - } - - { - int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode, - (share->pid == sys_getpid()),is_executable(fname)); - - if ((access_allowed == AFAIL) || - (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) || - (access_allowed == AREAD && *flags != O_RDONLY) || - (access_allowed == AWRITE && *flags != O_WRONLY)) { - - DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n", - deny_mode,old_deny_mode,old_open_mode, - (int)share->pid,fname, fcbopen, *flags, access_allowed)); - - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; - - return False; - } - - if (access_allowed == AREAD) - *flags = O_RDONLY; - - if (access_allowed == AWRITE) - *flags = O_WRONLY; - - } - - return True; -} - - -#if defined(DEVELOPER) -static void validate_my_share_entries(int num, share_mode_entry *share_entry) -{ - files_struct *fsp; - - if (share_entry->pid != sys_getpid()) - return; - - fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id); - if (!fsp) { - DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) )); - smb_panic("validate_my_share_entries: Cannot match a share entry with an open file\n"); - } - - if (((uint16)fsp->oplock_type) != share_entry->op_type) { - pstring str; - DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) )); - slprintf(str, sizeof(str)-1, "validate_my_share_entries: file %s, oplock_type = 0x%x, op_type = 0x%x\n", - fsp->fsp_name, (unsigned int)fsp->oplock_type, (unsigned int)share_entry->op_type ); - smb_panic(str); - } -} -#endif - -/**************************************************************************** - Deal with open deny mode and oplock break processing. - Invarient: Share mode must be locked on entry and exit. - Returns -1 on error, or number of share modes on success (may be zero). -****************************************************************************/ - -static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T dev, - SMB_INO_T inode, - uint32 desired_access, - int share_mode, int *p_flags, int *p_oplock_request, - BOOL *p_all_current_opens_are_level_II) -{ - int i; - int num_share_modes; - int oplock_contention_count = 0; - share_mode_entry *old_shares = 0; - BOOL fcbopen = False; - BOOL broke_oplock; - - if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB) - fcbopen = True; - - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); - - if(num_share_modes == 0) - return 0; - - /* - * Check if the share modes will give us access. - */ - - do { - share_mode_entry broken_entry; - - broke_oplock = False; - *p_all_current_opens_are_level_II = True; - - for(i = 0; i < num_share_modes; i++) { - share_mode_entry *share_entry = &old_shares[i]; - -#if defined(DEVELOPER) - validate_my_share_entries(i, share_entry); -#endif - - /* - * By observation of NetBench, oplocks are broken *before* share - * modes are checked. This allows a file to be closed by the client - * if the share mode would deny access and the client has an oplock. - * Check if someone has an oplock on this file. If so we must break - * it before continuing. - */ - - if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) || - (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) { - - BOOL opb_ret; - - DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \ -dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsigned int)dev, (double)inode)); - - /* Ensure the reply for the open uses the correct sequence number. */ - /* This isn't a real deferred packet as it's response will also increment - * the sequence. - */ - srv_defer_sign_response(get_current_mid()); - - /* Oplock break - unlock to request it. */ - unlock_share_entry(conn, dev, inode); - - opb_ret = request_oplock_break(share_entry, False); - - /* Now relock. */ - lock_share_entry(conn, dev, inode); - - 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)); - SAFE_FREE(old_shares); - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; - return -1; - } - - broke_oplock = True; - broken_entry = *share_entry; - break; - - } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { - *p_all_current_opens_are_level_II = False; - } - - /* someone else has a share lock on it, check to see if we can too */ - if (!check_share_mode(conn, share_entry, share_mode, desired_access, - fname, fcbopen, p_flags)) { - SAFE_FREE(old_shares); - errno = EACCES; - return -1; - } - - } /* end for */ - - if(broke_oplock) { - SAFE_FREE(old_shares); - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); - oplock_contention_count++; - - /* Paranoia check that this is no longer an exlusive entry. */ - for(i = 0; i < num_share_modes; i++) { - share_mode_entry *share_entry = &old_shares[i]; - - if (share_modes_identical(&broken_entry, share_entry) && - EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { - - /* - * This should not happen. The target left this oplock - * as exlusive.... The process *must* be dead.... - */ - - DEBUG(0,("open_mode_check: exlusive oplock left by process %d after break ! For file %s, \ -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)) { - DEBUG(0,("open_mode_check: Existent process %lu left active oplock.\n", - (unsigned long)broken_entry.pid )); - } - - if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) { - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; - return -1; - } - - /* - * We must reload the share modes after deleting the - * other process's entry. - */ - - SAFE_FREE(old_shares); - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); - break; - } - } /* end for paranoia... */ - } /* end if broke_oplock */ - - } while(broke_oplock); - - if(old_shares != 0) - SAFE_FREE(old_shares); - - /* - * Refuse to grant an oplock in case the contention limit is - * reached when going through the lock list multiple times. - */ - - if(oplock_contention_count >= lp_oplock_contention_limit(SNUM(conn))) { - *p_oplock_request = 0; - DEBUG(4,("open_mode_check: oplock contention = %d. Not granting oplock.\n", - oplock_contention_count )); - } - - return num_share_modes; -} - -/**************************************************************************** -set a kernel flock on a file for NFS interoperability -this requires a patch to Linux -****************************************************************************/ -static void kernel_flock(files_struct *fsp, int deny_mode) -{ -#if HAVE_KERNEL_SHARE_MODES - int kernel_mode = 0; - if (deny_mode == DENY_READ) kernel_mode = LOCK_MAND|LOCK_WRITE; - else if (deny_mode == DENY_WRITE) kernel_mode = LOCK_MAND|LOCK_READ; - else if (deny_mode == DENY_ALL) kernel_mode = LOCK_MAND; - if (kernel_mode) flock(fsp->fd, kernel_mode); -#endif - ;; -} - - -static BOOL open_match_attributes(connection_struct *conn, const char *path, uint32 old_dos_mode, uint32 new_dos_mode, - mode_t existing_mode, mode_t new_mode, mode_t *returned_mode) -{ - uint32 noarch_old_dos_mode, noarch_new_dos_mode; - - noarch_old_dos_mode = (old_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE); - noarch_new_dos_mode = (new_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE); - - if((noarch_old_dos_mode == 0 && noarch_new_dos_mode != 0) || - (noarch_old_dos_mode != 0 && ((noarch_old_dos_mode & noarch_new_dos_mode) == noarch_old_dos_mode))) - *returned_mode = new_mode; - else - *returned_mode = (mode_t)0; - - DEBUG(10,("open_match_attributes: file %s old_dos_mode = 0x%x, existing_mode = 0%o, new_dos_mode = 0x%x returned_mode = 0%o\n", - path, - old_dos_mode, (unsigned int)existing_mode, new_dos_mode, (unsigned int)*returned_mode )); - - /* If we're mapping SYSTEM and HIDDEN ensure they match. */ - if (lp_map_system(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { - if ((old_dos_mode & FILE_ATTRIBUTE_SYSTEM) && !(new_dos_mode & FILE_ATTRIBUTE_SYSTEM)) - return False; - } - if (lp_map_hidden(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { - if ((old_dos_mode & FILE_ATTRIBUTE_HIDDEN) && !(new_dos_mode & FILE_ATTRIBUTE_HIDDEN)) - return False; - } - return True; -} - -/**************************************************************************** - Open a file with a share mode. -****************************************************************************/ - -files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, - int share_mode,int ofun, uint32 new_dos_mode, int oplock_request, - int *Access,int *action) -{ - return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, new_dos_mode, - oplock_request, Access, action); -} - -/**************************************************************************** - Open a file with a share mode. -****************************************************************************/ - -files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, - uint32 desired_access, - int share_mode,int ofun, uint32 new_dos_mode, - int oplock_request, - int *Access,int *paction) -{ - int flags=0; - int flags2=0; - int deny_mode = GET_DENY_MODE(share_mode); - BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode); - BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); - BOOL file_existed = VALID_STAT(*psbuf); - BOOL fcbopen = False; - BOOL def_acl = False; - SMB_DEV_T dev = 0; - SMB_INO_T inode = 0; - int num_share_modes = 0; - BOOL all_current_opens_are_level_II = False; - BOOL fsp_open = False; - files_struct *fsp = NULL; - int open_mode=0; - uint16 port = 0; - mode_t new_mode = (mode_t)0; - int action; - uint32 existing_dos_mode = 0; - /* We add aARCH to this as this mode is only used if the file is created new. */ - mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname); - - if (conn->printer) { - /* printers are handled completely differently. Most of the passed parameters are - ignored */ - if (Access) - *Access = DOS_OPEN_WRONLY; - if (action) - *paction = FILE_WAS_CREATED; - return print_fsp_open(conn, fname); - } - - fsp = file_new(conn); - if(!fsp) - return NULL; - - DEBUG(10,("open_file_shared: fname = %s, dos_attrs = %x, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n", - fname, new_dos_mode, share_mode, ofun, (int)mode, oplock_request )); - - if (!check_name(fname,conn)) { - file_free(fsp); - return NULL; - } - - new_dos_mode &= SAMBA_ATTRIBUTES_MASK; - if (file_existed) { - existing_dos_mode = dos_mode(conn, fname, psbuf); - } - - /* ignore any oplock requests if oplocks are disabled */ - if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break) { - oplock_request = 0; - } - - /* this is for OS/2 EAs - try and say we don't support them */ - if (strstr(fname,".+,;=[].")) { - unix_ERR_class = ERRDOS; - /* OS/2 Workplace shell fix may be main code stream in a later release. */ -#if 1 /* OS2_WPS_FIX - Recent versions of OS/2 need this. */ - unix_ERR_code = ERRcannotopen; -#else /* OS2_WPS_FIX */ - unix_ERR_code = ERROR_EAS_NOT_SUPPORTED; -#endif /* OS2_WPS_FIX */ - - DEBUG(5,("open_file_shared: OS/2 EA's are not supported.\n")); - file_free(fsp); - return NULL; - } - - if ((GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) && file_existed) { - DEBUG(5,("open_file_shared: create new requested for file %s and file already exists.\n", - fname )); - file_free(fsp); - if (S_ISDIR(psbuf->st_mode)) { - errno = EISDIR; - } else { - errno = EEXIST; - } - return NULL; - } - - if (CAN_WRITE(conn) && (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST)) - flags2 |= O_CREAT; - - if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) - flags2 |= O_TRUNC; - - /* We only care about matching attributes on file exists and truncate. */ - if (file_existed && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) { - if (!open_match_attributes(conn, fname, existing_dos_mode, new_dos_mode, - psbuf->st_mode, mode, &new_mode)) { - DEBUG(5,("open_file_shared: attributes missmatch for file %s (%x %x) (0%o, 0%o)\n", - fname, existing_dos_mode, new_dos_mode, - (int)psbuf->st_mode, (int)mode )); - file_free(fsp); - errno = EACCES; - return NULL; - } - } - - if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) - flags2 |= O_EXCL; - - /* note that we ignore the append flag as - append does not mean the same thing under dos and unix */ - - switch (GET_OPEN_MODE(share_mode)) { - case DOS_OPEN_WRONLY: - flags = O_WRONLY; - if (desired_access == 0) - desired_access = FILE_WRITE_DATA; - break; - case DOS_OPEN_FCB: - fcbopen = True; - flags = O_RDWR; - if (desired_access == 0) - desired_access = FILE_READ_DATA|FILE_WRITE_DATA; - break; - case DOS_OPEN_RDWR: - flags = O_RDWR; - if (desired_access == 0) - desired_access = FILE_READ_DATA|FILE_WRITE_DATA; - break; - default: - flags = O_RDONLY; - if (desired_access == 0) - desired_access = FILE_READ_DATA; - break; - } - -#if defined(O_SYNC) - if (GET_FILE_SYNC_OPENMODE(share_mode)) { - flags2 |= O_SYNC; - } -#endif /* O_SYNC */ - - if (flags != O_RDONLY && file_existed && - (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_mode))) { - if (!fcbopen) { - DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n", - fname, !CAN_WRITE(conn) ? "share" : "file" )); - file_free(fsp); - errno = EACCES; - return NULL; - } - flags = O_RDONLY; - } - - if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) { - DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname)); - file_free(fsp); - errno = EINVAL; - return NULL; - } - - if (file_existed) { - - dev = psbuf->st_dev; - inode = psbuf->st_ino; - - lock_share_entry(conn, dev, inode); - - num_share_modes = open_mode_check(conn, fname, dev, inode, - desired_access, - share_mode, - &flags, &oplock_request, &all_current_opens_are_level_II); - if(num_share_modes == -1) { - - /* - * This next line is a subtlety we need for MS-Access. If a file open will - * fail due to share permissions and also for security (access) - * reasons, we need to return the access failed error, not the - * share error. This means we must attempt to open the file anyway - * in order to get the UNIX access error - even if we're going to - * fail the open for share reasons. This is bad, as we're burning - * another fd if there are existing locks but there's nothing else - * we can do. We also ensure we're not going to create or tuncate - * the file as we only want an access decision at this stage. JRA. - */ - errno = 0; - fsp_open = open_file(fsp,conn,fname,psbuf, - flags|(flags2&~(O_TRUNC|O_CREAT)),mode,desired_access); - - DEBUG(4,("open_file_shared : share_mode deny - calling open_file with \ -flags=0x%X flags2=0x%X mode=0%o returned %d\n", - flags,(flags2&~(O_TRUNC|O_CREAT)),(int)mode,(int)fsp_open )); - - if (!fsp_open && errno) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRnoaccess; - unix_ERR_ntstatus = NT_STATUS_ACCESS_DENIED; - } - - unlock_share_entry(conn, dev, inode); - if (fsp_open) - fd_close(conn, fsp); - file_free(fsp); - return NULL; - } - - /* - * We exit this block with the share entry *locked*..... - */ - } - - /* - * Ensure we pay attention to default ACLs on directories if required. - */ - - if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && - (def_acl = directory_has_default_acl(conn, parent_dirname(fname)))) - mode = 0777; - - DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", - flags,flags2,(int)mode)); - - /* - * open_file strips any O_TRUNC flags itself. - */ - - fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,mode,desired_access); - - if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT) && fcbopen) { - if((fsp_open = open_file(fsp,conn,fname,psbuf,O_RDONLY,mode,desired_access)) == True) - flags = O_RDONLY; - } - - if (!fsp_open) { - if(file_existed) - unlock_share_entry(conn, dev, inode); - file_free(fsp); - return NULL; - } - - /* - * Deal with the race condition where two smbd's detect the file doesn't - * exist and do the create at the same time. One of them will win and - * set a share mode, the other (ie. this one) should check if the - * requested share mode for this create is allowed. - */ - - if (!file_existed) { - - /* - * Now the file exists and fsp is successfully opened, - * fsp->dev and fsp->inode are valid and should replace the - * dev=0,inode=0 from a non existent file. Spotted by - * Nadav Danieli <nadavd@exanet.com>. JRA. - */ - - dev = fsp->dev; - inode = fsp->inode; - - lock_share_entry_fsp(fsp); - - num_share_modes = open_mode_check(conn, fname, dev, inode, - desired_access, - share_mode, - &flags, &oplock_request, &all_current_opens_are_level_II); - - if(num_share_modes == -1) { - unlock_share_entry_fsp(fsp); - fd_close(conn,fsp); - file_free(fsp); - return NULL; - } - - /* - * If there are any share modes set then the file *did* - * exist. Ensure we return the correct value for action. - */ - - if (num_share_modes > 0) - file_existed = True; - - /* - * We exit this block with the share entry *locked*..... - */ - } - - /* note that we ignore failure for the following. It is - basically a hack for NFS, and NFS will never set one of - these only read them. Nobody but Samba can ever set a deny - mode and we have already checked our more authoritative - locking database for permission to set this deny mode. If - the kernel refuses the operations then the kernel is wrong */ - kernel_flock(fsp, deny_mode); - - /* - * At this point onwards, we can guarentee that the share entry - * is locked, whether we created the file or not, and that the - * deny mode is compatible with all current opens. - */ - - /* - * If requested, truncate the file. - */ - - if (flags2&O_TRUNC) { - /* - * We are modifing the file after open - update the stat struct.. - */ - if ((truncate_unless_locked(conn,fsp) == -1) || (SMB_VFS_FSTAT(fsp,fsp->fd,psbuf)==-1)) { - unlock_share_entry_fsp(fsp); - fd_close(conn,fsp); - file_free(fsp); - return NULL; - } - } - - switch (flags) { - case O_RDONLY: - open_mode = DOS_OPEN_RDONLY; - break; - case O_RDWR: - open_mode = DOS_OPEN_RDWR; - break; - case O_WRONLY: - open_mode = DOS_OPEN_WRONLY; - break; - } - - fsp->share_mode = SET_DENY_MODE(deny_mode) | - SET_OPEN_MODE(open_mode) | - SET_ALLOW_SHARE_DELETE(allow_share_delete); - - DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode )); - - if (Access) { - (*Access) = open_mode; - } - - if (file_existed && !(flags2 & O_TRUNC)) - action = FILE_WAS_OPENED; - if (file_existed && (flags2 & O_TRUNC)) - action = FILE_WAS_OVERWRITTEN; - if (!file_existed) - action = FILE_WAS_CREATED; - - if (paction) { - *paction = action; - } - - /* - * Setup the oplock info in both the shared memory and - * file structs. - */ - - if(oplock_request && (num_share_modes == 0) && - !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) { - port = global_oplock_port; - } else if (oplock_request && all_current_opens_are_level_II) { - port = global_oplock_port; - oplock_request = LEVEL_II_OPLOCK; - set_file_oplock(fsp, oplock_request); - } else { - port = 0; - oplock_request = 0; - } - - 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)) { - /* Remember to delete the mode we just added. */ - del_share_mode(fsp, NULL); - unlock_share_entry_fsp(fsp); - fd_close(conn,fsp); - file_free(fsp); - return NULL; - } - } - - if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) { - /* Files should be initially set as archive */ - if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { - file_set_dosmode(conn, fname, new_dos_mode | aARCH, NULL); - } - } - - /* - * Take care of inherited ACLs on created files - if default ACL not - * selected. - */ - - if (!file_existed && !def_acl) { - - int saved_errno = errno; /* We might get ENOSYS in the next call.. */ - - if (SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, mode) == -1 && errno == ENOSYS) - errno = saved_errno; /* Ignore ENOSYS */ - - } else if (new_mode) { - - int ret = -1; - - /* Attributes need changing. File already existed. */ - - { - int saved_errno = errno; /* We might get ENOSYS in the next call.. */ - ret = SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, new_mode); - - if (ret == -1 && errno == ENOSYS) { - errno = saved_errno; /* Ignore ENOSYS */ - } else { - DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n", - fname, (int)new_mode)); - ret = 0; /* Don't do the fchmod below. */ - } - } - - if ((ret == -1) && (SMB_VFS_FCHMOD(fsp, fsp->fd, new_mode) == -1)) - DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n", - fname, (int)new_mode)); - } - - unlock_share_entry_fsp(fsp); - - conn->num_files_open++; - - return fsp; -} - -/**************************************************************************** - Open a file for for write to ensure that we can fchmod it. -****************************************************************************/ - -files_struct *open_file_fchmod(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) -{ - files_struct *fsp = NULL; - BOOL fsp_open; - - if (!VALID_STAT(*psbuf)) - return NULL; - - fsp = file_new(conn); - if(!fsp) - return NULL; - - /* note! we must use a non-zero desired access or we don't get - a real file descriptor. Oh what a twisted web we weave. */ - fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA); - - /* - * This is not a user visible file open. - * Don't set a share mode and don't increment - * the conn->num_files_open. - */ - - if (!fsp_open) { - file_free(fsp); - return NULL; - } - - return fsp; -} - -/**************************************************************************** - Close the fchmod file fd - ensure no locks are lost. -****************************************************************************/ - -int close_file_fchmod(files_struct *fsp) -{ - int ret = fd_close(fsp->conn, fsp); - file_free(fsp); - return ret; -} - -/**************************************************************************** - Open a directory from an NT SMB call. -****************************************************************************/ - -files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf, - uint32 desired_access, int share_mode, int smb_ofun, 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; - - if (VALID_STAT(*psbuf)) - got_stat = True; - - if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) { - file_free(fsp); - errno = EEXIST; /* Setup so correct error is returned to client. */ - return NULL; - } - - if (GET_FILE_CREATE_DISPOSITION(smb_ofun) == FILE_CREATE_IF_NOT_EXIST) { - - if (got_stat) { - - if(!S_ISDIR(psbuf->st_mode)) { - DEBUG(0,("open_directory: %s is not a directory !\n", fname )); - file_free(fsp); - errno = EACCES; - return NULL; - } - *action = FILE_WAS_OPENED; - - } else { - - /* - * Try and create the directory. - */ - - if(!CAN_WRITE(conn)) { - DEBUG(2,("open_directory: failing create on read-only share\n")); - file_free(fsp); - errno = EACCES; - return NULL; - } - - if (ms_has_wild(fname)) { - file_free(fsp); - DEBUG(5,("open_directory: failing create on filename %s with wildcards\n", fname)); - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRinvalidname; - unix_ERR_ntstatus = NT_STATUS_OBJECT_NAME_INVALID; - return NULL; - } - - if( strchr_m(fname, ':')) { - file_free(fsp); - DEBUG(5,("open_directory: failing create on filename %s with colon in name\n", fname)); - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRinvalidname; - unix_ERR_ntstatus = NT_STATUS_NOT_A_DIRECTORY; - return NULL; - } - - if(vfs_MkDir(conn,fname, unix_mode(conn,aDIR, fname)) < 0) { - DEBUG(2,("open_directory: unable to create %s. Error was %s\n", - fname, strerror(errno) )); - file_free(fsp); - return NULL; - } - - if(SMB_VFS_STAT(conn,fname, psbuf) != 0) { - file_free(fsp); - return NULL; - } - - *action = FILE_WAS_CREATED; - - } - } else { - - /* - * Don't create - just check that it *was* a directory. - */ - - if(!got_stat) { - DEBUG(3,("open_directory: unable to stat name = %s. Error was %s\n", - fname, strerror(errno) )); - file_free(fsp); - return NULL; - } - - if(!S_ISDIR(psbuf->st_mode)) { - DEBUG(0,("open_directory: %s is not a directory !\n", fname )); - file_free(fsp); - return NULL; - } - - *action = FILE_WAS_OPENED; - } - - DEBUG(5,("open_directory: opening directory %s\n", fname)); - - /* - * Setup the files_struct for it. - */ - - fsp->mode = psbuf->st_mode; - fsp->inode = psbuf->st_ino; - fsp->dev = psbuf->st_dev; - fsp->size = psbuf->st_size; - fsp->vuid = current_user.vuid; - fsp->file_pid = global_smbpid; - fsp->can_lock = True; - fsp->can_read = False; - fsp->can_write = False; - fsp->share_mode = share_mode; - fsp->desired_access = desired_access; - fsp->print_file = False; - fsp->modified = False; - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = True; - fsp->is_stat = False; - fsp->directory_delete_on_close = False; - string_set(&fsp->fsp_name,fname); - - 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; - } - } - conn->num_files_open++; - - return fsp; -} - -/**************************************************************************** - Open a pseudo-file (no locking checks - a 'stat' open). -****************************************************************************/ - -files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf) -{ - extern struct current_user current_user; - files_struct *fsp = NULL; - - if (!VALID_STAT(*psbuf)) - return NULL; - - /* Can't 'stat' open directories. */ - if(S_ISDIR(psbuf->st_mode)) - return NULL; - - fsp = file_new(conn); - if(!fsp) - return NULL; - - DEBUG(5,("open_file_stat: 'opening' file %s\n", fname)); - - /* - * Setup the files_struct for it. - */ - - fsp->mode = psbuf->st_mode; - /* - * Don't store dev or inode, we don't want any iterator - * to see this. - */ - fsp->inode = (SMB_INO_T)0; - fsp->dev = (SMB_DEV_T)0; - fsp->size = psbuf->st_size; - fsp->vuid = current_user.vuid; - fsp->file_pid = global_smbpid; - fsp->can_lock = False; - fsp->can_read = False; - fsp->can_write = False; - fsp->share_mode = 0; - fsp->desired_access = 0; - fsp->print_file = False; - fsp->modified = False; - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = False; - fsp->is_stat = True; - fsp->directory_delete_on_close = False; - string_set(&fsp->fsp_name,fname); - - conn->num_files_open++; - - return fsp; -} diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c deleted file mode 100644 index 19e6956d9ef..00000000000 --- a/source/smbd/oplock.c +++ /dev/null @@ -1,1260 +0,0 @@ -/* - Unix SMB/CIFS implementation. - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* Oplock ipc UDP socket. */ -static int oplock_sock = -1; -uint16 global_oplock_port = 0; - -/* Current number of oplocks we have outstanding. */ -static int32 exclusive_oplocks_open = 0; -static int32 level_II_oplocks_open = 0; -BOOL global_client_failed_oplock_break = False; -BOOL global_oplock_break = False; - -extern int smb_read_error; - -static struct kernel_oplocks *koplocks; - -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. -****************************************************************************/ - -int32 get_number_of_exclusive_open_oplocks(void) -{ - return exclusive_oplocks_open; -} - -/**************************************************************************** - Return True if an oplock message is pending. -****************************************************************************/ - -BOOL oplock_message_waiting(fd_set *fds) -{ - if (koplocks && koplocks->msg_waiting(fds)) - return True; - - if (FD_ISSET(oplock_sock, fds)) - return True; - - return False; -} - -/**************************************************************************** - Read an oplock break message from either the oplock UDP fd or the - kernel (if kernel oplocks are supported). - - If timeout is zero then *fds contains the file descriptors that - are ready to be read and acted upon. If timeout is non-zero then - *fds contains the file descriptors to be selected on for read. - The timeout is in milliseconds - -****************************************************************************/ - -BOOL receive_local_message( char *buffer, int buffer_len, int timeout) -{ - struct sockaddr_in from; - socklen_t fromlen = sizeof(from); - int32 msg_len = 0; - fd_set fds; - int selrtn = -1; - - FD_ZERO(&fds); - smb_read_error = 0; - - /* - * We need to check for kernel oplocks before going into the select - * here, as the EINTR generated by the linux kernel oplock may have - * already been eaten. JRA. - */ - - if (koplocks && koplocks->msg_waiting(&fds)) { - return koplocks->receive_message(&fds, buffer, buffer_len); - } - - while (timeout > 0 && selrtn == -1) { - struct timeval to; - int maxfd = oplock_sock; - time_t starttime = time(NULL); - - FD_ZERO(&fds); - maxfd = setup_oplock_select_set(&fds); - - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; - - DEBUG(5,("receive_local_message: doing select with timeout of %d ms\n", timeout)); - - 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); - } - - /* - * Linux 2.0.x seems to have a bug in that - * it can return -1, EINTR with a timeout of zero. - * Make sure we bail out here with a read timeout - * if we got EINTR on a timeout of 1 or less. - */ - - if (timeout <= 1) { - smb_read_error = READ_TIMEOUT; - return False; - } - - /* Not a kernel interrupt - could be a SIGUSR1 message. We must restart. */ - /* We need to decrement the timeout here. */ - timeout -= ((time(NULL) - starttime)*1000); - if (timeout < 0) - timeout = 1; - - DEBUG(5,("receive_local_message: EINTR : new timeout %d ms\n", timeout)); - continue; - } - - /* 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 = sys_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)) - return False; - - fsp->oplock_type = oplock_type; - fsp->sent_oplock_break = NO_BREAK_SENT; - if (oplock_type == LEVEL_II_OPLOCK) - level_II_oplocks_open++; - else - exclusive_oplocks_open++; - - 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; -} - -/**************************************************************************** - Attempt to release an oplock on a file. Decrements oplock count. -****************************************************************************/ - -void release_file_oplock(files_struct *fsp) -{ - if ((fsp->oplock_type != NO_OPLOCK) && koplocks) - koplocks->release_oplock(fsp); - - if (fsp->oplock_type == LEVEL_II_OPLOCK) - level_II_oplocks_open--; - else if (fsp->oplock_type) - exclusive_oplocks_open--; - - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - - flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH); -} - -/**************************************************************************** - Attempt to downgrade an oplock on a file. Doesn't decrement oplock count. -****************************************************************************/ - -static void downgrade_file_oplock(files_struct *fsp) -{ - if (koplocks) - koplocks->release_oplock(fsp); - fsp->oplock_type = LEVEL_II_OPLOCK; - exclusive_oplocks_open--; - level_II_oplocks_open++; - fsp->sent_oplock_break = NO_BREAK_SENT; -} - -/**************************************************************************** - Remove a file oplock. Copes with level II and exclusive. - Locks then unlocks the share mode lock. Client can decide to go directly - to none even if a "break-to-level II" was sent. -****************************************************************************/ - -BOOL remove_oplock(files_struct *fsp, BOOL break_to_none) -{ - SMB_DEV_T dev = fsp->dev; - SMB_INO_T inode = fsp->inode; - BOOL ret = True; - - /* Remove the oplock flag from the sharemode. */ - if (lock_share_entry_fsp(fsp) == False) { - DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n", - fsp->fsp_name )); - return False; - } - - if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT || break_to_none) { - /* - * Deal with a reply when a break-to-none was sent. - */ - - if(remove_share_oplock(fsp)==False) { - DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \ -dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode)); - ret = False; - } - - release_file_oplock(fsp); - } else { - /* - * Deal with a reply when a break-to-level II was sent. - */ - if(downgrade_share_oplock(fsp)==False) { - DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \ -dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode)); - ret = False; - } - - downgrade_file_oplock(fsp); - } - - unlock_share_entry_fsp(fsp); - return ret; -} - -/**************************************************************************** - Setup the listening set of file descriptors for an oplock break - message either from the UDP socket or from the kernel. Returns the maximum - fd used. -****************************************************************************/ - -int setup_oplock_select_set( fd_set *fds) -{ - int maxfd = oplock_sock; - - if(oplock_sock == -1) - return 0; - - FD_SET(oplock_sock,fds); - - if (koplocks && koplocks->notification_fd != -1) { - FD_SET(koplocks->notification_fd, fds); - maxfd = MAX(maxfd, koplocks->notification_fd); - } - - return maxfd; -} - -/**************************************************************************** - 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; - 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: - case ASYNC_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 \ -(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)); - 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 async level II case. - */ - - if(break_cmd_type == OPLOCK_BREAK_CMD || break_cmd_type == LEVEL_II_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,break_cmd_type | 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(sys_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; -} - -/**************************************************************************** - Set up an oplock break message. -****************************************************************************/ - -static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2) -{ - memset(outbuf,'\0',smb_size); - set_message(outbuf,8,0,True); - - SCVAL(outbuf,smb_com,SMBlockingX); - SSVAL(outbuf,smb_tid,fsp->conn->cnum); - SSVAL(outbuf,smb_pid,0xFFFF); - SSVAL(outbuf,smb_uid,0); - SSVAL(outbuf,smb_mid,0xFFFF); - SCVAL(outbuf,smb_vwv0,0xFF); - SSVAL(outbuf,smb_vwv2,fsp->fnum); - SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE); - SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); -} - -/**************************************************************************** - Function to do the waiting before sending a local break. -****************************************************************************/ - -static void wait_before_sending_break(BOOL local_request) -{ - extern struct timeval smb_last_time; - - if(local_request) { - struct timeval cur_tv; - long wait_left = (long)lp_oplock_break_wait_time(); - - if (wait_left == 0) - return; - - GetTimeOfDay(&cur_tv); - - 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); - } - } -} - -/**************************************************************************** - Ensure that we have a valid oplock. -****************************************************************************/ - -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 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; -} - -/**************************************************************************** - Process a level II oplock break directly. -****************************************************************************/ - -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."); - } - - /* - * 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 )); - } - - release_file_oplock(fsp); - - if (!local_request && got_lock) - unlock_share_entry_fsp(fsp); - - 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, 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; - BOOL sign_state; - 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; - - /* Save the server smb signing state. */ - sign_state = srv_oplock_set_signing(False); - - if (!send_smb(smbd_server_fd(), outbuf)) { - srv_oplock_set_signing(sign_state); - exit_server("oplock_break: send_smb failed."); - } - - /* Restore the sign state to what it was. */ - srv_oplock_set_signing(sign_state); - - /* 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; - change_to_root_user(); - vfs_GetWd(saved_fsp_conn,saved_dir); - /* 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_BAD_SIG) { - DEBUG( 0, ("oplock_break: bad signature from client\n" )); - 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); -#if FASCIST_OPLOCK_BACKOFF - global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */ -#endif - } - - /* - * 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; -} - -/**************************************************************************** -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, BOOL async) -{ - 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; - uint16 break_cmd_type; - - 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; - } - - DEBUG(5,("request_oplock_break: breaking our own oplock\n")); - -#if 1 /* JRA PARANOIA TEST.... */ - { - 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, 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)) { - break_cmd_type = async ? ASYNC_LEVEL_II_OPLOCK_BREAK_CMD : LEVEL_II_OPLOCK_BREAK_CMD; - } else { - break_cmd_type = OPLOCK_BREAK_CMD; - } - - SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,break_cmd_type); - 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 %s oplock break message to ", async ? "asynchronous" : "synchronous" ); - 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(sys_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 in async mode then - * we are done and may return. - */ - - if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type) && async) { - DEBUG(3,("request_oplock_break: sent async 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; - - if(receive_local_message(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 (ie. the one we sent with the CMD_REPLY flag OR'ed in). - */ - if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) && - ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == break_cmd_type) && - (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; -} - -/**************************************************************************** - Attempt to break an oplock on a file (if oplocked). - Returns True if the file was closed as a result of - the oplock break, False otherwise. - 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)); - - 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; -} - -/**************************************************************************** - This function is called on any file modification or lock request. If a file - is level 2 oplocked then it must tell all other level 2 holders to break to none. -****************************************************************************/ - -void release_level_2_oplocks_on_change(files_struct *fsp) -{ - share_mode_entry *share_list = NULL; - pid_t pid = sys_getpid(); - int token = -1; - int num_share_modes = 0; - int i; - - /* - * If this file is level II oplocked then we need - * to grab the shared memory lock and inform all - * other files with a level II lock that they need - * to flush their read caches. We keep the lock over - * the shared memory area whilst doing this. - */ - - if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) - return; - - if (lock_share_entry_fsp(fsp) == False) { - DEBUG(0,("release_level_2_oplocks_on_change: failed to lock share mode entry for file %s.\n", fsp->fsp_name )); - } - - num_share_modes = get_share_modes(fsp->conn, fsp->dev, fsp->inode, &share_list); - - DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", - num_share_modes )); - - for(i = 0; i < num_share_modes; i++) { - share_mode_entry *share_entry = &share_list[i]; - - /* - * As there could have been multiple writes waiting at the lock_share_entry - * gate we may not be the first to enter. Hence the state of the op_types - * in the share mode entries may be partly NO_OPLOCK and partly LEVEL_II - * oplock. It will do no harm to re-send break messages to those smbd's - * that are still waiting their turn to remove their LEVEL_II state, and - * also no harm to ignore existing NO_OPLOCK states. JRA. - */ - - DEBUG(10,("release_level_2_oplocks_on_change: share_entry[%i]->op_type == %d\n", - i, share_entry->op_type )); - - if (share_entry->op_type == NO_OPLOCK) - continue; - - /* Paranoia .... */ - if (EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) { - DEBUG(0,("release_level_2_oplocks_on_change: PANIC. share mode entry %d is an exlusive oplock !\n", i )); - unlock_share_entry(fsp->conn, fsp->dev, fsp->inode); - abort(); - } - - /* - * Check if this is a file we have open (including the - * file we've been called to do write_file on. If so - * then break it directly without releasing the lock. - */ - - if (pid == share_entry->pid) { - files_struct *new_fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id); - - /* Paranoia check... */ - if(new_fsp == NULL) { - DEBUG(0,("release_level_2_oplocks_on_change: PANIC. share mode entry %d is not a local file !\n", i )); - unlock_share_entry(fsp->conn, fsp->dev, fsp->inode); - abort(); - } - - DEBUG(10,("release_level_2_oplocks_on_change: breaking our own oplock.\n")); - - oplock_break_level2(new_fsp, True, token); - - } else { - - /* - * This is a remote file and so we send an asynchronous - * message. - */ - - DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock (async).\n")); - request_oplock_break(share_entry, True); - } - } - - SAFE_FREE(share_list); - unlock_share_entry_fsp(fsp); - - /* Paranoia check... */ - if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) { - DEBUG(0,("release_level_2_oplocks_on_change: PANIC. File %s still has a level II oplock.\n", fsp->fsp_name)); - smb_panic("release_level_2_oplocks_on_change"); - } -} - -/**************************************************************************** -setup oplocks for this process -****************************************************************************/ - -BOOL init_oplocks(void) -{ - struct sockaddr_in sock_name; - socklen_t len = sizeof(sock_name); - - DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n")); - - /* Open a lookback UDP socket on a random port. */ - oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False); - if (oplock_sock == -1) { - DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \ -address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno))); - global_oplock_port = 0; - return(False); - } - - /* Find out the transient UDP port we have been allocated. */ - if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0) { - DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n", - strerror(errno))); - close(oplock_sock); - oplock_sock = -1; - global_oplock_port = 0; - return False; - } - global_oplock_port = ntohs(sock_name.sin_port); - - if (lp_kernel_oplocks()) { -#if HAVE_KERNEL_OPLOCKS_IRIX - koplocks = irix_init_kernel_oplocks(); -#elif HAVE_KERNEL_OPLOCKS_LINUX - koplocks = linux_init_kernel_oplocks(); -#endif - } - - DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n", - (int)sys_getpid(), global_oplock_port)); - - return True; -} diff --git a/source/smbd/oplock_irix.c b/source/smbd/oplock_irix.c deleted file mode 100644 index ffcf3d0af4d..00000000000 --- a/source/smbd/oplock_irix.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - Unix SMB/CIFS implementation. - IRIX kernel oplock processing - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#if HAVE_KERNEL_OPLOCKS_IRIX - -static int oplock_pipe_write = -1; -static int oplock_pipe_read = -1; - -/**************************************************************************** - Test to see if IRIX kernel oplocks work. -****************************************************************************/ - -static BOOL irix_oplocks_available(void) -{ - int fd; - int pfd[2]; - pstring tmpname; - - oplock_set_capability(True, False); - - slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid()); - - if(pipe(pfd) != 0) { - DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n", - strerror(errno) )); - return False; - } - - if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) { - DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n", - tmpname, strerror(errno) )); - unlink( tmpname ); - close(pfd[0]); - close(pfd[1]); - return False; - } - - unlink(tmpname); - - if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) { - DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \ -Disabling kernel oplock support.\n" )); - close(pfd[0]); - close(pfd[1]); - close(fd); - return False; - } - - if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) { - DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \ -Disabling kernel oplock support.\n", strerror(errno) )); - close(pfd[0]); - close(pfd[1]); - close(fd); - return False; - } - - close(pfd[0]); - close(pfd[1]); - close(fd); - - 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; - 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,("irix_oplock_receive_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(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { - DEBUG(0,("irix_oplock_receive_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; - } - - /* - * 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,("irix_oplock_receive_message: unable to find open file with dev = %x, inode = %.0f\n", - (unsigned int)os.os_dev, (double)os.os_ino )); - return False; - } - - DEBUG(5,("irix_oplock_receive_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 )); - - /* - * 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; - - 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 (sys_fcntl_long(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) { - if(errno != EAGAIN) { - DEBUG(0,("irix_set_kernel_oplock: Unable to get kernel oplock on file %s, dev = %x, \ -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,("irix_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ -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,("irix_set_kernel_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)) { - /* - * Check and print out the current kernel - * oplock state of this file. - */ - int state = sys_fcntl_long(fsp->fd, F_OPLKACK, -1); - dbgtext("irix_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, fsp->file_id, state ); - } - - /* - * Remove the kernel oplock on this file. - */ - if(sys_fcntl_long(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) { - if( DEBUGLVL( 0 )) { - dbgtext("irix_release_kernel_oplock: Error when removing kernel oplock on file " ); - dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n", - fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, fsp->file_id, strerror(errno) ); - } - } -} - -/**************************************************************************** - 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, unsigned long *file_id) -{ - /* Ensure that the msg length is correct. */ - if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) { - DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n", - msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN)); - 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 *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id)); - - 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. -****************************************************************************/ - -static BOOL irix_oplock_msg_waiting(fd_set *fds) -{ - if (oplock_pipe_read == -1) - return False; - - return FD_ISSET(oplock_pipe_read,fds); -} - -/**************************************************************************** - 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(pipe(pfd) != 0) { - DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n", - strerror(errno) )); - return False; - } - - oplock_pipe_read = pfd[0]; - oplock_pipe_write = pfd[1]; - - koplocks.receive_message = irix_oplock_receive_message; - koplocks.set_oplock = irix_set_kernel_oplock; - koplocks.release_oplock = irix_release_kernel_oplock; - koplocks.parse_message = irix_kernel_oplock_parse; - koplocks.msg_waiting = irix_oplock_msg_waiting; - koplocks.notification_fd = oplock_pipe_read; - - 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 deleted file mode 100644 index 5de9dd56e68..00000000000 --- a/source/smbd/oplock_linux.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - Unix SMB/CIFS implementation. - kernel oplock processing for Linux - Copyright (C) Andrew Tridgell 2000 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#if HAVE_KERNEL_OPLOCKS_LINUX - -static SIG_ATOMIC_T signals_received; -#define FD_PENDING_SIZE 100 -static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE]; - -#ifndef F_SETLEASE -#define F_SETLEASE 1024 -#endif - -#ifndef F_GETLEASE -#define F_GETLEASE 1025 -#endif - -#ifndef CAP_LEASE -#define CAP_LEASE 28 -#endif - -#ifndef RT_SIGNAL_LEASE -#define RT_SIGNAL_LEASE (SIGRTMIN+1) -#endif - -#ifndef F_SETSIG -#define F_SETSIG 10 -#endif - -/**************************************************************************** - Handle a LEASE signal, incrementing the signals_received and blocking the signal. -****************************************************************************/ - -static void signal_handler(int sig, siginfo_t *info, void *unused) -{ - if (signals_received < FD_PENDING_SIZE - 1) { - fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd; - signals_received++; - } /* Else signal is lost. */ - sys_select_signal(); -} - -/**************************************************************************** - Try to gain a linux capability. -****************************************************************************/ - -static void set_capability(unsigned capability) -{ -#ifndef _LINUX_CAPABILITY_VERSION -#define _LINUX_CAPABILITY_VERSION 0x19980330 -#endif - /* these can be removed when they are in glibc headers */ - struct { - uint32 version; - int pid; - } header; - struct { - uint32 effective; - uint32 permitted; - uint32 inheritable; - } data; - - header.version = _LINUX_CAPABILITY_VERSION; - header.pid = 0; - - if (capget(&header, &data) == -1) { - DEBUG(3,("Unable to get kernel capabilities (%s)\n", strerror(errno))); - return; - } - - data.effective |= (1<<capability); - - if (capset(&header, &data) == -1) { - DEBUG(3,("Unable to set %d capability (%s)\n", - capability, strerror(errno))); - } -} - -/**************************************************************************** - 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; - - if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) { - DEBUG(3,("Failed to set signal handler for kernel lease\n")); - return -1; - } - - ret = fcntl(fd, F_SETLEASE, leasetype); - if (ret == -1 && errno == EACCES) { - set_capability(CAP_LEASE); - ret = fcntl(fd, F_SETLEASE, 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) -{ - int fd; - struct files_struct *fsp; - - BlockSignals(True, RT_SIGNAL_LEASE); - fd = fd_pending_array[0]; - fsp = file_find_fd(fd); - fd_pending_array[0] = (SIG_ATOMIC_T)-1; - if (signals_received > 1) - memmove((void *)&fd_pending_array[0], (void *)&fd_pending_array[1], - sizeof(SIG_ATOMIC_T)*(signals_received-1)); - signals_received--; - /* now we can receive more signals */ - BlockSignals(False, RT_SIGNAL_LEASE); - - if (fsp == NULL) { - DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd)); - return False; - } - - DEBUG(3,("linux_oplock_receive_message: kernel oplock break request received for \ -dev = %x, inode = %.0f fd = %d, fileid = %lu \n", (unsigned int)fsp->dev, (double)fsp->inode, - fd, fsp->file_id)); - - /* - * 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; - - 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 linux_set_kernel_oplock(files_struct *fsp, int oplock_type) -{ - if (linux_setlease(fsp->fd, F_WRLCK) == -1) { - DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ -inode = %.0f. (%s)\n", - fsp->fsp_name, fsp->fd, - (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno))); - return False; - } - - DEBUG(3,("linux_set_kernel_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)) { - /* - * Check and print out the current kernel - * oplock state of this file. - */ - int state = fcntl(fsp->fd, F_GETLEASE, 0); - dbgtext("linux_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, fsp->file_id, state ); - } - - /* - * Remove the kernel oplock on this file. - */ - if (linux_setlease(fsp->fd, F_UNLCK) == -1) { - if (DEBUGLVL(0)) { - dbgtext("linux_release_kernel_oplock: Error when removing kernel oplock on file " ); - dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n", - fsp->fsp_name, (unsigned int)fsp->dev, - (double)fsp->inode, fsp->file_id, strerror(errno) ); - } - } -} - -/**************************************************************************** - 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, unsigned long *file_id) -{ - /* Ensure that the msg length is correct. */ - if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) { - DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %lu).\n", - msg_len, (unsigned long)KERNEL_OPLOCK_BREAK_MSG_LEN)); - 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 *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id)); - - 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. -****************************************************************************/ - -static BOOL linux_oplock_msg_waiting(fd_set *fds) -{ - return signals_received != 0; -} - -/**************************************************************************** - 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! */ - ret = fcntl(fd, F_GETLEASE, 0); - close(fd); - return ret == F_UNLCK; -} - -/**************************************************************************** - Setup kernel oplocks. -****************************************************************************/ - -struct kernel_oplocks *linux_init_kernel_oplocks(void) -{ - static struct kernel_oplocks koplocks; - struct sigaction act; - - if (!linux_oplocks_available()) { - DEBUG(3,("Linux kernel oplocks not available\n")); - return NULL; - } - - ZERO_STRUCT(act); - - act.sa_handler = NULL; - act.sa_sigaction = signal_handler; - act.sa_flags = SA_SIGINFO; - sigemptyset( &act.sa_mask ); - 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; - koplocks.release_oplock = linux_release_kernel_oplock; - koplocks.parse_message = linux_kernel_oplock_parse; - koplocks.msg_waiting = linux_oplock_msg_waiting; - koplocks.notification_fd = -1; - - /* the signal can start off blocked due to a bug in bash */ - BlockSignals(False, RT_SIGNAL_LEASE); - - DEBUG(3,("Linux kernel oplocks enabled\n")); - - 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 deleted file mode 100644 index 9f6dad423ad..00000000000 --- a/source/smbd/password.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* users from session setup */ -static pstring session_users=""; - -/* this holds info on user ids that are already validated for this VC */ -static user_struct *validated_users; -static int next_vuid = VUID_OFFSET; -static int num_validated_vuids; - -extern userdom_struct current_user_info; - - -/**************************************************************************** - 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; - int count=0; - - if (vuid == UID_FIELD_INVALID) - return NULL; - - for (usp=validated_users;usp;usp=usp->next,count++) { - if (vuid == usp->vuid) { - if (count > 10) { - DLIST_PROMOTE(validated_users, usp); - } - return usp; - } - } - - return NULL; -} - -/**************************************************************************** - Invalidate a uid. -****************************************************************************/ - -void invalidate_vuid(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - - if (vuser == NULL) - return; - - SAFE_FREE(vuser->homedir); - SAFE_FREE(vuser->unix_homedir); - SAFE_FREE(vuser->logon_script); - - session_yield(vuser); - SAFE_FREE(vuser->session_keystr); - - free_server_info(&vuser->server_info); - - data_blob_free(&vuser->session_key); - - DLIST_REMOVE(validated_users, vuser); - - /* clear the vuid from the 'cache' on each connection, and - from the vuid 'owner' of connections */ - conn_clear_vuid_cache(vuid); - - SAFE_FREE(vuser->groups); - delete_nt_token(&vuser->nt_user_token); - destroy_privilege(&vuser->privs); - SAFE_FREE(vuser); - num_validated_vuids--; -} - -/**************************************************************************** - Invalidate all vuid entries for this process. -****************************************************************************/ - -void invalidate_all_vuids(void) -{ - user_struct *usp, *next=NULL; - - for (usp=validated_users;usp;usp=next) { - next = usp->next; - - invalidate_vuid(usp->vuid); - } -} - -/** - * register that a valid login has been performed, establish 'session'. - * @param server_info The token returned from the authentication process. - * (now 'owned' by register_vuid) - * - * @param session_key The User session key for the login session (now also 'owned' by register_vuid) - * - * @param respose_blob The NT challenge-response, if available. (May be freed after this call) - * - * @param smb_name The untranslated name of the user - * - * @return Newly allocated vuid, biased by an offset. (This allows us to - * tell random client vuid's (normally zero) from valid vuids.) - * - */ - -int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name) -{ - user_struct *vuser = NULL; - - /* Ensure no vuid gets registered in share level security. */ - if(lp_security() == SEC_SHARE) { - data_blob_free(&session_key); - return UID_FIELD_INVALID; - } - - /* Limit allowed vuids to 16bits - VUID_OFFSET. */ - if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) { - data_blob_free(&session_key); - return UID_FIELD_INVALID; - } - - if((vuser = (user_struct *)malloc( sizeof(user_struct) )) == NULL) { - DEBUG(0,("Failed to malloc users struct!\n")); - data_blob_free(&session_key); - return UID_FIELD_INVALID; - } - - ZERO_STRUCTP(vuser); - - /* Allocate a free vuid. Yes this is a linear search... :-) */ - while( get_valid_user_struct(next_vuid) != NULL ) { - next_vuid++; - /* Check for vuid wrap. */ - if (next_vuid == UID_FIELD_INVALID) - next_vuid = VUID_OFFSET; - } - - DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); - - vuser->vuid = next_vuid; - - /* the next functions should be done by a SID mapping system (SMS) as - * the new real sam db won't have reference to unix uids or gids - */ - - vuser->uid = server_info->uid; - vuser->gid = server_info->gid; - - vuser->n_groups = server_info->n_groups; - if (vuser->n_groups) { - if (!(vuser->groups = memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) { - DEBUG(0,("register_vuid: failed to memdup vuser->groups\n")); - data_blob_free(&session_key); - free(vuser); - free_server_info(&server_info); - return UID_FIELD_INVALID; - } - } - - vuser->guest = server_info->guest; - fstrcpy(vuser->user.unix_name, server_info->unix_name); - - /* This is a potentially untrusted username */ - alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", sizeof(vuser->user.smb_name)); - - fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); - fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account)); - - { - /* Keep the homedir handy */ - const char *homedir = pdb_get_homedir(server_info->sam_account); - const char *logon_script = pdb_get_logon_script(server_info->sam_account); - - if (!IS_SAM_DEFAULT(server_info->sam_account, PDB_UNIXHOMEDIR)) { - const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); - if (unix_homedir) { - vuser->unix_homedir = smb_xstrdup(unix_homedir); - } - } else { - struct passwd *passwd = getpwnam_alloc(vuser->user.unix_name); - if (passwd) { - vuser->unix_homedir = smb_xstrdup(passwd->pw_dir); - passwd_free(&passwd); - } - } - - if (homedir) { - vuser->homedir = smb_xstrdup(homedir); - } - if (logon_script) { - vuser->logon_script = smb_xstrdup(logon_script); - } - } - - vuser->session_key = session_key; - - DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", - (unsigned int)vuser->uid, - (unsigned int)vuser->gid, - vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, vuser->guest )); - - DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name)); - - if (server_info->ptok) { - vuser->nt_user_token = dup_nt_token(server_info->ptok); - } else { - DEBUG(1, ("server_info does not contain a user_token - cannot continue\n")); - free_server_info(&server_info); - data_blob_free(&session_key); - SAFE_FREE(vuser->homedir); - SAFE_FREE(vuser->unix_homedir); - SAFE_FREE(vuser->logon_script); - - SAFE_FREE(vuser); - return UID_FIELD_INVALID; - } - - if (server_info->privs) { - init_privilege(&(vuser->privs)); - dup_priv_set(vuser->privs, server_info->privs); - } - - /* use this to keep tabs on all our info from the authentication */ - vuser->server_info = server_info; - - DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",(int)vuser->uid,vuser->user.unix_name, vuser->vuid)); - - next_vuid++; - num_validated_vuids++; - - DLIST_ADD(validated_users, vuser); - - if (!session_claim(vuser)) { - DEBUG(1,("Failed to claim session for vuid=%d\n", vuser->vuid)); - invalidate_vuid(vuser->vuid); - return -1; - } - - /* Register a home dir service for this user iff - (a) This is not a guest connection, - (b) we have a home directory defined, and - (c) there s not an existing static share by that name */ - - if ( (!vuser->guest) - && vuser->unix_homedir - && *(vuser->unix_homedir) - && (lp_servicenumber(vuser->user.unix_name) == -1) ) - { - DEBUG(3, ("Adding/updating homes service for user '%s' using home directory: '%s'\n", - vuser->user.unix_name, vuser->unix_homedir)); - - vuser->homes_snum = add_home_service(vuser->user.unix_name, - vuser->user.unix_name, vuser->unix_homedir); - } else { - vuser->homes_snum = -1; - } - - if (srv_is_signing_negotiated() && !vuser->guest && !srv_signing_started()) { - /* Try and turn on server signing on the first non-guest sessionsetup. */ - srv_set_signing(vuser->session_key, response_blob); - } - - /* fill in the current_user_info struct */ - set_current_user_info( &vuser->user ); - - - return vuser->vuid; -} - -/**************************************************************************** - Add a name to the session users list. -****************************************************************************/ - -void add_session_user(const char *user) -{ - fstring suser; - struct passwd *passwd; - - if (!(passwd = Get_Pwnam(user))) - return; - - fstrcpy(suser,passwd->pw_name); - - 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); - } - } -} - -/**************************************************************************** - Check if a username is valid. -****************************************************************************/ - -BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) -{ - char **valid, **invalid; - BOOL ret; - - valid = invalid = NULL; - ret = True; - - if (lp_invalid_users(snum)) { - str_list_copy(&invalid, lp_invalid_users(snum)); - if (invalid && str_list_substitute(invalid, "%S", lp_servicename(snum))) { - if ( invalid && str_list_sub_basic(invalid, current_user_info.smb_name) ) { - ret = !user_in_list(user, (const char **)invalid, groups, n_groups); - } - } - } - if (invalid) - str_list_free (&invalid); - - if (ret && lp_valid_users(snum)) { - str_list_copy(&valid, lp_valid_users(snum)); - if ( valid && str_list_substitute(valid, "%S", lp_servicename(snum)) ) { - if ( valid && str_list_sub_basic(valid, current_user_info.smb_name) ) { - ret = user_in_list(user, (const char **)valid, groups, n_groups); - } - } - } - if (valid) - str_list_free (&valid); - - if (ret && lp_onlyuser(snum)) { - char **user_list = str_list_make (lp_username(snum), NULL); - if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { - ret = user_in_list(user, (const char **)user_list, groups, n_groups); - } - if (user_list) str_list_free (&user_list); - } - - return(ret); -} - -/**************************************************************************** - Validate a group username entry. Return the username or NULL. -****************************************************************************/ - -static char *validate_group(char *group, DATA_BLOB password,int snum) -{ -#ifdef HAVE_NETGROUP - { - char *host, *user, *domain; - setnetgrent(group); - while (getnetgrent(&host, &user, &domain)) { - if (user) { - if (user_ok(user, snum, NULL, 0) && - password_ok(user,password)) { - endnetgrent(); - return(user); - } - } - } - endnetgrent(); - } -#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'; - } - } - - endgrent(); - - member = member_list; - while (*member) { - static fstring name; - fstrcpy(name,member); - if (user_ok(name,snum, NULL, 0) && - password_ok(name,password)) { - endgrent(); - return(&name[0]); - } - - DEBUG(10,("validate_group = member = %s\n", member)); - - member += strlen(member) + 1; - } - } else { - endgrent(); - return NULL; - } - } -#endif - return(NULL); -} - -/**************************************************************************** - Check for authority to login to a service with a given username/password. - Note this is *NOT* used when logging on using sessionsetup_and_X. -****************************************************************************/ - -BOOL authorise_login(int snum, fstring user, DATA_BLOB password, - BOOL *guest) -{ - BOOL ok = False; - -#if DEBUG_PASSWORD - DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n", - user,password.data)); -#endif - - *guest = False; - - /* there are several possibilities: - 1) login as the given user with given password - 2) login as a previously registered username with the given password - 3) login as a session list username with the given password - 4) login as a previously validated user/password pair - 5) login as the "user =" user with given password - 6) login as the "user =" user with no password (guest connection) - 7) login as guest user with no password - - if the service is guest_only then steps 1 to 5 are skipped - */ - - /* now check the list of session users */ - if (!ok) { - char *auser; - char *user_list = strdup(session_users); - if (!user_list) - return(False); - - for (auser=strtok(user_list,LIST_SEP); !ok && auser; - auser = strtok(NULL,LIST_SEP)) { - fstring user2; - fstrcpy(user2,auser); - if (!user_ok(user2,snum, NULL, 0)) - continue; - - if (password_ok(user2,password)) { - ok = True; - fstrcpy(user,user2); - DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \ -and given password ok\n", user)); - } - } - - SAFE_FREE(user_list); - } - - /* check the user= fields and the given password */ - if (!ok && lp_username(snum)) { - char *auser; - pstring user_list; - pstrcpy(user_list,lp_username(snum)); - - pstring_sub(user_list,"%S",lp_servicename(snum)); - - for (auser=strtok(user_list,LIST_SEP); auser && !ok; - auser = strtok(NULL,LIST_SEP)) { - if (*auser == '@') { - auser = validate_group(auser+1,password,snum); - if (auser) { - ok = True; - fstrcpy(user,auser); - DEBUG(3,("authorise_login: ACCEPTED: group username \ -and given password ok (%s)\n", user)); - } - } else { - fstring user2; - fstrcpy(user2,auser); - if (user_ok(user2,snum, NULL, 0) && password_ok(user2,password)) { - ok = True; - fstrcpy(user,user2); - DEBUG(3,("authorise_login: ACCEPTED: user list username \ -and given password ok (%s)\n", user)); - } - } - } - } - - /* check for a normal guest connection */ - if (!ok && GUEST_OK(snum)) { - fstring guestname; - fstrcpy(guestname,lp_guestaccount()); - if (Get_Pwnam(guestname)) { - fstrcpy(user,guestname); - ok = True; - DEBUG(3,("authorise_login: ACCEPTED: guest account and guest ok (%s)\n", - user)); - } else { - DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname)); - } - *guest = True; - } - - if (ok && !user_ok(user, snum, NULL, 0)) { - DEBUG(0,("authorise_login: rejected invalid user %s\n",user)); - ok = False; - } - - return(ok); -} diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c deleted file mode 100644 index f7e9c595c13..00000000000 --- a/source/smbd/pipes.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Pipe SMB reply routines - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Luke Kenneth Casson Leighton 1996-1998 - Copyright (C) Paul Ashton 1997-1998. - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This file handles reply_ calls on named pipes that the server - makes to handle specific protocols -*/ - - -#include "includes.h" - -#define PIPE "\\PIPE\\" -#define PIPELEN strlen(PIPE) - -extern struct pipe_id_info pipe_names[]; - -/**************************************************************************** - reply to an open and X on a named pipe - - This code is basically stolen from reply_open_and_X with some - wrinkles to handle pipes. -****************************************************************************/ -int reply_open_pipe_and_X(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - pstring fname; - pstring pipe_name; - uint16 vuid = SVAL(inbuf, smb_uid); - smb_np_struct *p; - int smb_ofun = SVAL(inbuf,smb_vwv8); - int size=0,fmode=0,mtime=0,rmode=0; - int i; - - /* XXXX we need to handle passed times, sattr and flags */ - srvstr_pull_buf(inbuf, pipe_name, smb_buf(inbuf), sizeof(pipe_name), STR_TERMINATE); - - /* If the name doesn't start \PIPE\ then this is directed */ - /* at a mailslot or something we really, really don't understand, */ - /* not just something we really don't understand. */ - if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) - return(ERROR_DOS(ERRSRV,ERRaccess)); - - DEBUG(4,("Opening pipe %s.\n", pipe_name)); - - /* See if it is one we want to handle. */ - for( i = 0; pipe_names[i].client_pipe ; i++ ) - if( strequal(pipe_name,pipe_names[i].client_pipe) ) - break; - - if (pipe_names[i].client_pipe == NULL) - return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); - - /* Strip \PIPE\ off the name. */ - pstrcpy(fname, pipe_name + PIPELEN); - - -#if 0 - /* - * Hack for NT printers... JRA. - */ - if(should_fail_next_srvsvc_open(fname)) - return(ERROR(ERRSRV,ERRaccess)); -#endif - - /* Known pipes arrive with DIR attribs. Remove it so a regular file */ - /* can be opened and add it in after the open. */ - DEBUG(3,("Known pipe %s opening.\n",fname)); - smb_ofun |= FILE_CREATE_IF_NOT_EXIST; - - p = open_rpc_pipe_p(fname, conn, vuid); - if (!p) return(ERROR_DOS(ERRSRV,ERRnofids)); - - /* Prepare the reply */ - set_message(outbuf,15,0,True); - - /* Mark the opened file as an existing named pipe in message mode. */ - SSVAL(outbuf,smb_vwv9,2); - SSVAL(outbuf,smb_vwv10,0xc700); - - if (rmode == 2) { - DEBUG(4,("Resetting open result to open from create.\n")); - rmode = 1; - } - - SSVAL(outbuf,smb_vwv2, p->pnum); - SSVAL(outbuf,smb_vwv3,fmode); - put_dos_date3(outbuf,smb_vwv4,mtime); - SIVAL(outbuf,smb_vwv6,size); - SSVAL(outbuf,smb_vwv8,rmode); - SSVAL(outbuf,smb_vwv11,0x0001); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - reply to a write on a pipe -****************************************************************************/ -int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) -{ - smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0); - size_t numtowrite = SVAL(inbuf,smb_vwv1); - int nwritten; - int outsize; - char *data; - - if (!p) - return(ERROR_DOS(ERRDOS,ERRbadfid)); - - data = smb_buf(inbuf) + 3; - - if (numtowrite == 0) - nwritten = 0; - else - nwritten = write_to_pipe(p, data, numtowrite); - - if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) - return (UNIXERROR(ERRDOS,ERRnoaccess)); - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - - DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", - p->pnum, nwritten)); - - return(outsize); -} - -/**************************************************************************** - Reply to a write and X. - - This code is basically stolen from reply_write_and_X with some - wrinkles to handle pipes. -****************************************************************************/ - -int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2); - size_t numtowrite = SVAL(inbuf,smb_vwv10); - int nwritten = -1; - int smb_doff = SVAL(inbuf, smb_vwv11); - BOOL pipe_start_message_raw = ((SVAL(inbuf, smb_vwv7) & (PIPE_START_MESSAGE|PIPE_RAW_MODE)) == - (PIPE_START_MESSAGE|PIPE_RAW_MODE)); - char *data; - - if (!p) - return(ERROR_DOS(ERRDOS,ERRbadfid)); - - data = smb_base(inbuf) + smb_doff; - - if (numtowrite == 0) - nwritten = 0; - else { - if(pipe_start_message_raw) { - /* - * For the start of a message in named pipe byte mode, - * the first two bytes are a length-of-pdu field. Ignore - * them (we don't trust the client. JRA. - */ - if(numtowrite < 2) { - DEBUG(0,("reply_pipe_write_and_X: start of message set and not enough data sent.(%u)\n", - (unsigned int)numtowrite )); - return (UNIXERROR(ERRDOS,ERRnoaccess)); - } - - data += 2; - numtowrite -= 2; - } - nwritten = write_to_pipe(p, data, numtowrite); - } - - if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) - return (UNIXERROR(ERRDOS,ERRnoaccess)); - - set_message(outbuf,6,0,True); - - nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten); - SSVAL(outbuf,smb_vwv2,nwritten); - - DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", - p->pnum, nwritten)); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - reply to a read and X - - This code is basically stolen from reply_read_and_X with some - wrinkles to handle pipes. -****************************************************************************/ -int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2); - int smb_maxcnt = SVAL(inbuf,smb_vwv5); - int smb_mincnt = SVAL(inbuf,smb_vwv6); - int nread = -1; - char *data; - BOOL unused; - - /* we don't use the offset given to use for pipe reads. This - is deliberate, instead we always return the next lump of - data on the pipe */ -#if 0 - uint32 smb_offs = IVAL(inbuf,smb_vwv3); -#endif - - if (!p) - return(ERROR_DOS(ERRDOS,ERRbadfid)); - - set_message(outbuf,12,0,True); - data = smb_buf(outbuf); - - nread = read_from_pipe(p, data, smb_maxcnt, &unused); - - if (nread < 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - SSVAL(outbuf,smb_vwv5,nread); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,nread); - - DEBUG(3,("readX-IPC pnum=%04x min=%d max=%d nread=%d\n", - p->pnum, smb_mincnt, smb_maxcnt, nread)); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - reply to a close -****************************************************************************/ -int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf) -{ - smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0); - int outsize = set_message(outbuf,0,0,True); - - if (!p) - return(ERROR_DOS(ERRDOS,ERRbadfid)); - - DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum)); - - if (!close_rpc_pipe_hnd(p)) - return ERROR_DOS(ERRDOS,ERRbadfid); - - return(outsize); -} diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c deleted file mode 100644 index 620e123e14d..00000000000 --- a/source/smbd/posix_acls.c +++ /dev/null @@ -1,3382 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB NT Security Descriptor / Unix permission conversion. - Copyright (C) Jeremy Allison 1994-2000. - Copyright (C) Andreas Gruenbacher 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/**************************************************************************** - Data structures representing the internal ACE format. -****************************************************************************/ - -enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE}; -enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */ - -typedef union posix_id { - uid_t uid; - gid_t gid; - int world; -} posix_id; - -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 trustee; - enum ace_owner owner_type; - enum ace_attribute attr; - posix_id unix_ug; - BOOL inherited; -} canon_ace; - -#define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR) - -/* - * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance) - * attribute on disk. - * - * | 1 | 1 | 2 | 2 | .... - * +------+------+-------------+---------------------+-------------+--------------------+ - * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... | - * +------+------+-------------+---------------------+-------------+--------------------+ - */ - -#define PAI_VERSION_OFFSET 0 -#define PAI_FLAG_OFFSET 1 -#define PAI_NUM_ENTRIES_OFFSET 2 -#define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4 -#define PAI_ENTRIES_BASE 6 - -#define PAI_VERSION 1 -#define PAI_ACL_FLAG_PROTECTED 0x1 -#define PAI_ENTRY_LENGTH 5 - -/* - * In memory format of user.SAMBA_PAI attribute. - */ - -struct pai_entry { - struct pai_entry *next, *prev; - enum ace_owner owner_type; - posix_id unix_ug; -}; - -struct pai_val { - BOOL protected; - unsigned int num_entries; - struct pai_entry *entry_list; - unsigned int num_def_entries; - struct pai_entry *def_entry_list; -}; - -/************************************************************************ - Return a uint32 of the pai_entry principal. -************************************************************************/ - -static uint32 get_pai_entry_val(struct pai_entry *paie) -{ - switch (paie->owner_type) { - case UID_ACE: - DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid )); - return (uint32)paie->unix_ug.uid; - case GID_ACE: - DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid )); - return (uint32)paie->unix_ug.gid; - case WORLD_ACE: - default: - DEBUG(10,("get_pai_entry_val: world ace\n")); - return (uint32)-1; - } -} - -/************************************************************************ - Return a uint32 of the entry principal. -************************************************************************/ - -static uint32 get_entry_val(canon_ace *ace_entry) -{ - switch (ace_entry->owner_type) { - case UID_ACE: - DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid )); - return (uint32)ace_entry->unix_ug.uid; - case GID_ACE: - DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid )); - return (uint32)ace_entry->unix_ug.gid; - case WORLD_ACE: - default: - DEBUG(10,("get_entry_val: world ace\n")); - return (uint32)-1; - } -} - -/************************************************************************ - Count the inherited entries. -************************************************************************/ - -static unsigned int num_inherited_entries(canon_ace *ace_list) -{ - unsigned int num_entries = 0; - - for (; ace_list; ace_list = ace_list->next) - if (ace_list->inherited) - num_entries++; - return num_entries; -} - -/************************************************************************ - Create the on-disk format. Caller must free. -************************************************************************/ - -static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size) -{ - char *pai_buf = NULL; - canon_ace *ace_list = NULL; - char *entry_offset = NULL; - unsigned int num_entries = 0; - unsigned int num_def_entries = 0; - - for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) - if (ace_list->inherited) - num_entries++; - - for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) - if (ace_list->inherited) - num_def_entries++; - - DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries )); - - *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH); - - pai_buf = malloc(*store_size); - if (!pai_buf) { - return NULL; - } - - /* Set up the header. */ - memset(pai_buf, '\0', PAI_ENTRIES_BASE); - SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION); - SCVAL(pai_buf,PAI_FLAG_OFFSET,(protected ? PAI_ACL_FLAG_PROTECTED : 0)); - SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries); - SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries); - - entry_offset = pai_buf + PAI_ENTRIES_BASE; - - for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) { - if (ace_list->inherited) { - uint8 type_val = (unsigned char)ace_list->owner_type; - uint32 entry_val = get_entry_val(ace_list); - - SCVAL(entry_offset,0,type_val); - SIVAL(entry_offset,1,entry_val); - entry_offset += PAI_ENTRY_LENGTH; - } - } - - for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) { - if (ace_list->inherited) { - uint8 type_val = (unsigned char)ace_list->owner_type; - uint32 entry_val = get_entry_val(ace_list); - - SCVAL(entry_offset,0,type_val); - SIVAL(entry_offset,1,entry_val); - entry_offset += PAI_ENTRY_LENGTH; - } - } - - return pai_buf; -} - -/************************************************************************ - Store the user.SAMBA_PAI attribute on disk. -************************************************************************/ - -static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list, - canon_ace *dir_ace_list, BOOL protected) -{ - int ret; - size_t store_size; - char *pai_buf; - - if (!lp_map_acl_inherit(SNUM(fsp->conn))) - return; - - /* - * Don't store if this ACL isn't protected and - * none of the entries in it are marked as inherited. - */ - - if (!protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) { - /* Instead just remove the attribute if it exists. */ - if (fsp->fd != -1) - SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME); - else - SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME); - return; - } - - pai_buf = create_pai_buf(file_ace_list, dir_ace_list, protected, &store_size); - - if (fsp->fd != -1) - ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, store_size, 0); - else - ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, store_size, 0); - - SAFE_FREE(pai_buf); - - DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp->fsp_name)); - if (ret == -1 && errno != ENOSYS) - DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) )); -} - -/************************************************************************ - Delete the in memory inheritance info. -************************************************************************/ - -static void free_inherited_info(struct pai_val *pal) -{ - if (pal) { - struct pai_entry *paie, *paie_next; - for (paie = pal->entry_list; paie; paie = paie_next) { - paie_next = paie->next; - SAFE_FREE(paie); - } - for (paie = pal->def_entry_list; paie; paie = paie_next) { - paie_next = paie->next; - SAFE_FREE(paie); - } - SAFE_FREE(pal); - } -} - -/************************************************************************ - Was this ACL protected ? -************************************************************************/ - -static BOOL get_protected_flag(struct pai_val *pal) -{ - if (!pal) - return False; - return pal->protected; -} - -/************************************************************************ - Was this ACE inherited ? -************************************************************************/ - -static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace) -{ - struct pai_entry *paie; - - if (!pal) - return False; - - /* If the entry exists it is inherited. */ - for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) { - if (ace_entry->owner_type == paie->owner_type && - get_entry_val(ace_entry) == get_pai_entry_val(paie)) - return True; - } - return False; -} - -/************************************************************************ - Ensure an attribute just read is valid. -************************************************************************/ - -static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size) -{ - uint16 num_entries; - uint16 num_def_entries; - - if (pai_buf_data_size < PAI_ENTRIES_BASE) { - /* Corrupted - too small. */ - return False; - } - - if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION) - return False; - - num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET); - num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET); - - /* Check the entry lists match. */ - /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */ - - if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size) - return False; - - return True; -} - - -/************************************************************************ - Convert to in-memory format. -************************************************************************/ - -static struct pai_val *create_pai_val(char *buf, size_t size) -{ - char *entry_offset; - struct pai_val *paiv = NULL; - int i; - - if (!check_pai_ok(buf, size)) - return NULL; - - paiv = malloc(sizeof(struct pai_val)); - if (!paiv) - return NULL; - - memset(paiv, '\0', sizeof(struct pai_val)); - - paiv->protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED); - - paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET); - paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET); - - entry_offset = buf + PAI_ENTRIES_BASE; - - DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n", - paiv->protected ? " (protected)" : "", paiv->num_entries, paiv->num_def_entries )); - - for (i = 0; i < paiv->num_entries; i++) { - struct pai_entry *paie; - - paie = malloc(sizeof(struct pai_entry)); - if (!paie) { - free_inherited_info(paiv); - return NULL; - } - - paie->owner_type = (enum ace_owner)CVAL(entry_offset,0); - switch( paie->owner_type) { - case UID_ACE: - paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1); - DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid )); - break; - case GID_ACE: - paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1); - DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid )); - break; - case WORLD_ACE: - paie->unix_ug.world = -1; - DEBUG(10,("create_pai_val: world ace\n")); - break; - default: - free_inherited_info(paiv); - return NULL; - } - entry_offset += PAI_ENTRY_LENGTH; - DLIST_ADD(paiv->entry_list, paie); - } - - for (i = 0; i < paiv->num_def_entries; i++) { - struct pai_entry *paie; - - paie = malloc(sizeof(struct pai_entry)); - if (!paie) { - free_inherited_info(paiv); - return NULL; - } - - paie->owner_type = (enum ace_owner)CVAL(entry_offset,0); - switch( paie->owner_type) { - case UID_ACE: - paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1); - DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid )); - break; - case GID_ACE: - paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1); - DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid )); - break; - case WORLD_ACE: - paie->unix_ug.world = -1; - DEBUG(10,("create_pai_val: (def) world ace\n")); - break; - default: - free_inherited_info(paiv); - return NULL; - } - entry_offset += PAI_ENTRY_LENGTH; - DLIST_ADD(paiv->def_entry_list, paie); - } - - return paiv; -} - -/************************************************************************ - Load the user.SAMBA_PAI attribute. -************************************************************************/ - -static struct pai_val *load_inherited_info(files_struct *fsp) -{ - char *pai_buf; - size_t pai_buf_size = 1024; - struct pai_val *paiv = NULL; - ssize_t ret; - - if (!lp_map_acl_inherit(SNUM(fsp->conn))) - return NULL; - - if ((pai_buf = malloc(pai_buf_size)) == NULL) - return NULL; - - do { - if (fsp->fd != -1) - ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, pai_buf_size); - else - ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, pai_buf_size); - - if (ret == -1) { - if (errno != ERANGE) { - break; - } - /* Buffer too small - enlarge it. */ - pai_buf_size *= 2; - SAFE_FREE(pai_buf); - if ((pai_buf = malloc(pai_buf_size)) == NULL) - return NULL; - } - } while (ret == -1); - - DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name)); - - if (ret == -1) { - /* No attribute or not supported. */ -#if defined(ENOATTR) - if (errno != ENOATTR) - DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); -#else - if (errno != ENOSYS) - DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); -#endif - SAFE_FREE(pai_buf); - return NULL; - } - - paiv = create_pai_val(pai_buf, ret); - - if (paiv && paiv->protected) - DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name)); - - SAFE_FREE(pai_buf); - return paiv; -} - -/**************************************************************************** - Functions to manipulate the internal ACE format. -****************************************************************************/ - -/**************************************************************************** - Count a linked list of canonical ACE entries. -****************************************************************************/ - -static size_t count_canon_ace_list( canon_ace *list_head ) -{ - size_t count = 0; - canon_ace *ace; - - for (ace = list_head; ace; ace = ace->next) - count++; - - return count; -} - -/**************************************************************************** - Free a linked list of canonical ACE entries. -****************************************************************************/ - -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); - SAFE_FREE(old_head); - } -} - -/**************************************************************************** - Function to duplicate a canon_ace entry. -****************************************************************************/ - -static canon_ace *dup_canon_ace( canon_ace *src_ace) -{ - canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace)); - - if (dst_ace == NULL) - return NULL; - - *dst_ace = *src_ace; - dst_ace->prev = dst_ace->next = NULL; - return dst_ace; -} - -/**************************************************************************** - Print out a canon ace. -****************************************************************************/ - -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->trustee)); - if (pace->owner_type == UID_ACE) { - const 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) { - 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) { - case SMB_ACL_USER: - dbgtext( "SMB_ACL_USER "); - break; - case SMB_ACL_USER_OBJ: - dbgtext( "SMB_ACL_USER_OBJ "); - break; - case SMB_ACL_GROUP: - dbgtext( "SMB_ACL_GROUP "); - break; - case SMB_ACL_GROUP_OBJ: - dbgtext( "SMB_ACL_GROUP_OBJ "); - break; - case SMB_ACL_OTHER: - dbgtext( "SMB_ACL_OTHER "); - break; - } - if (pace->inherited) - dbgtext( "(inherited) "); - dbgtext( "perms "); - dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-'); - dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-'); - dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-'); -} - -/**************************************************************************** - Print out a canon ace list. -****************************************************************************/ - -static void print_canon_ace_list(const char *name, canon_ace *ace_list) -{ - int count = 0; - - if( DEBUGLVL( 10 )) { - dbgtext( "print_canon_ace_list: %s\n", name ); - for (;ace_list; ace_list = ace_list->next, count++) - print_canon_ace(ace_list, count ); - } -} - -/**************************************************************************** - Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits). -****************************************************************************/ - -static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset) -{ - mode_t ret = 0; - - ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0); - ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0); - ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0); - - return ret; -} - -/**************************************************************************** - Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits). -****************************************************************************/ - -static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask) -{ - mode_t ret = 0; - - if (mode & r_mask) - ret |= S_IRUSR; - if (mode & w_mask) - ret |= S_IWUSR; - if (mode & x_mask) - ret |= S_IXUSR; - - return ret; -} - -/**************************************************************************** - Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to - an SMB_ACL_PERMSET_T. -****************************************************************************/ - -static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset) -{ - if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) - return -1; - if (mode & S_IRUSR) { - if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) - return -1; - } - if (mode & S_IWUSR) { - if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) - return -1; - } - if (mode & S_IXUSR) { - if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) - return -1; - } - return 0; -} -/**************************************************************************** - Function to create owner and group SIDs from a SMB_STRUCT_STAT. -****************************************************************************/ - -static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid) -{ - uid_to_sid( powner_sid, psbuf->st_uid ); - gid_to_sid( pgroup_sid, psbuf->st_gid ); -} - -/**************************************************************************** - Merge aces with a common sid - if both are allow or deny, OR the permissions together and - delete the second one. If the first is deny, mask the permissions off and delete the allow - if the permissions become zero, delete the deny if the permissions are non zero. -****************************************************************************/ - -static void merge_aces( canon_ace **pp_list_head ) -{ - canon_ace *list_head = *pp_list_head; - canon_ace *curr_ace_outer; - canon_ace *curr_ace_outer_next; - - /* - * First, merge allow entries with identical SIDs, and deny entries - * with identical SIDs. - */ - - for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) { - canon_ace *curr_ace; - canon_ace *curr_ace_next; - - curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */ - - for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) { - - curr_ace_next = curr_ace->next; /* Save the link in case of delete. */ - - if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && - (curr_ace->attr == curr_ace_outer->attr)) { - - if( DEBUGLVL( 10 )) { - dbgtext("merge_aces: Merging ACE's\n"); - print_canon_ace( curr_ace_outer, 0); - print_canon_ace( curr_ace, 0); - } - - /* Merge two allow or two deny ACE's. */ - - curr_ace_outer->perms |= curr_ace->perms; - DLIST_REMOVE(list_head, curr_ace); - SAFE_FREE(curr_ace); - curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ - } - } - } - - /* - * Now go through and mask off allow permissions with deny permissions. - * We can delete either the allow or deny here as we know that each SID - * appears only once in the list. - */ - - for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) { - canon_ace *curr_ace; - canon_ace *curr_ace_next; - - curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */ - - for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) { - - curr_ace_next = curr_ace->next; /* Save the link in case of delete. */ - - /* - * Subtract ACE's with different entries. Due to the ordering constraints - * we've put on the ACL, we know the deny must be the first one. - */ - - if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && - (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) { - - if( DEBUGLVL( 10 )) { - dbgtext("merge_aces: Masking ACE's\n"); - print_canon_ace( curr_ace_outer, 0); - print_canon_ace( curr_ace, 0); - } - - curr_ace->perms &= ~curr_ace_outer->perms; - - if (curr_ace->perms == 0) { - - /* - * The deny overrides the allow. Remove the allow. - */ - - DLIST_REMOVE(list_head, curr_ace); - SAFE_FREE(curr_ace); - curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ - - } else { - - /* - * Even after removing permissions, there - * are still allow permissions - delete the deny. - * It is safe to delete the deny here, - * as we are guarenteed by the deny first - * ordering that all the deny entries for - * this SID have already been merged into one - * before we can get to an allow ace. - */ - - DLIST_REMOVE(list_head, curr_ace_outer); - SAFE_FREE(curr_ace_outer); - break; - } - } - - } /* end for curr_ace */ - } /* end for curr_ace_outer */ - - /* We may have modified the list. */ - - *pp_list_head = list_head; -} - -/**************************************************************************** - Check if we need to return NT4.x compatible ACL entries. -****************************************************************************/ - -static BOOL nt4_compatible_acls(void) -{ - const char *compat = lp_acl_compatibility(); - - if (*compat == '\0') { - enum remote_arch_types ra_type = get_remote_arch(); - - /* Automatically adapt to client */ - return (ra_type <= RA_WINNT); - } else - return (strequal(compat, "winnt")); -} - - -/**************************************************************************** - Map canon_ace perms to permission bits NT. - The attr element is not used here - we only process deny entries on set, - not get. Deny entries are implicit on get with ace->perms = 0. -****************************************************************************/ - -static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace) -{ - SEC_ACCESS sa; - uint32 nt_mask = 0; - - *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED; - - if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) { - nt_mask = UNIX_ACCESS_RWX; - } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) { - /* - * Windows NT refuses to display ACEs with no permissions in them (but - * they are perfectly legal with Windows 2000). If the ACE has empty - * permissions we cannot use 0, so we use the otherwise unused - * WRITE_OWNER permission, which we ignore when we set an ACL. - * We abstract this into a #define of UNIX_ACCESS_NONE to allow this - * to be changed in the future. - */ - - if (nt4_compatible_acls()) - nt_mask = UNIX_ACCESS_NONE; - else - nt_mask = 0; - } else { - nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 ); - nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); - nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); - } - - DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n", - (unsigned int)ace->perms, (unsigned int)nt_mask )); - - init_sec_access(&sa,nt_mask); - return sa; -} - -/**************************************************************************** - Map NT perms to a UNIX mode_t. -****************************************************************************/ - -#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES) -#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES) -#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE) - -static mode_t map_nt_perms( SEC_ACCESS sec_access, int type) -{ - mode_t mode = 0; - - switch(type) { - case S_IRUSR: - if(sec_access.mask & GENERIC_ALL_ACCESS) - mode = S_IRUSR|S_IWUSR|S_IXUSR; - else { - mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0; - mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0; - mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0; - } - break; - case S_IRGRP: - if(sec_access.mask & GENERIC_ALL_ACCESS) - mode = S_IRGRP|S_IWGRP|S_IXGRP; - else { - mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0; - mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0; - mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0; - } - break; - case S_IROTH: - if(sec_access.mask & GENERIC_ALL_ACCESS) - mode = S_IROTH|S_IWOTH|S_IXOTH; - else { - mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0; - mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0; - mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0; - } - break; - } - - return mode; -} - -/**************************************************************************** - Unpack a SEC_DESC into a UNIX owner and group. -****************************************************************************/ - -static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) -{ - DOM_SID owner_sid; - DOM_SID grp_sid; - - *puser = (uid_t)-1; - *pgrp = (gid_t)-1; - - if(security_info_sent == 0) { - DEBUG(0,("unpack_nt_owners: no security info sent !\n")); - return True; - } - - /* - * Validate the owner and group SID's. - */ - - memset(&owner_sid, '\0', sizeof(owner_sid)); - memset(&grp_sid, '\0', sizeof(grp_sid)); - - DEBUG(5,("unpack_nt_owners: validating owner_sids.\n")); - - /* - * Don't immediately fail if the owner sid cannot be validated. - * This may be a group chown only set. - */ - - if (security_info_sent & OWNER_SECURITY_INFORMATION) { - sid_copy(&owner_sid, psd->owner_sid); - if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) { -#if ACL_FORCE_UNMAPPABLE - /* this allows take ownership to work reasonably */ - extern struct current_user current_user; - *puser = current_user.uid; -#else - DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n", - sid_string_static(&owner_sid))); - return False; -#endif - } - } - - /* - * Don't immediately fail if the group sid cannot be validated. - * This may be an owner chown only set. - */ - - if (security_info_sent & GROUP_SECURITY_INFORMATION) { - sid_copy(&grp_sid, psd->grp_sid); - if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) { -#if ACL_FORCE_UNMAPPABLE - /* this allows take group ownership to work reasonably */ - extern struct current_user current_user; - *pgrp = current_user.gid; -#else - DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n")); - return False; -#endif - } - } - - DEBUG(5,("unpack_nt_owners: owner_sids validated.\n")); - - return True; -} - -/**************************************************************************** - Ensure the enforced permissions for this share apply. -****************************************************************************/ - -static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) -{ - int snum = SNUM(fsp->conn); - mode_t and_bits = (mode_t)0; - mode_t or_bits = (mode_t)0; - - /* Get the initial bits to apply. */ - - if (fsp->is_directory) { - and_bits = lp_dir_security_mask(snum); - or_bits = lp_force_dir_security_mode(snum); - } else { - and_bits = lp_security_mask(snum); - or_bits = lp_force_security_mode(snum); - } - - /* Now bounce them into the S_USR space. */ - switch(type) { - case S_IRUSR: - /* Ensure owner has read access. */ - pace->perms |= S_IRUSR; - if (fsp->is_directory) - pace->perms |= (S_IWUSR|S_IXUSR); - and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR); - or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR); - break; - case S_IRGRP: - and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP); - or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP); - break; - case S_IROTH: - and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH); - or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH); - break; - } - - pace->perms = ((pace->perms & and_bits)|or_bits); -} - -/**************************************************************************** - Check if a given uid/SID is in a group gid/SID. This is probably very - expensive and will need optimisation. A *lot* of optimisation :-). JRA. -****************************************************************************/ - -static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) -{ - extern DOM_SID global_sid_World; - fstring u_name; - fstring g_name; - extern struct current_user current_user; - - /* "Everyone" always matches every uid. */ - - if (sid_equal(&group_ace->trustee, &global_sid_World)) - return True; - - /* Assume that the current user is in the current group (force group) */ - - if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid) - return True; - - 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(u_name, g_name, NULL, 0); -} - -/**************************************************************************** - A well formed POSIX file or default ACL has at least 3 entries, a - SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ. - In addition, the owner must always have at least read access. - When using this call on get_acl, the pst struct is valid and contains - the mode of the file. When using this call on set_acl, the pst struct has - been modified to have a mode containing the default for this file or directory - type. -****************************************************************************/ - -static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, - files_struct *fsp, - DOM_SID *pfile_owner_sid, - DOM_SID *pfile_grp_sid, - SMB_STRUCT_STAT *pst, - BOOL setting_acl) -{ - extern DOM_SID global_sid_World; - canon_ace *pace; - BOOL got_user = False; - BOOL got_grp = False; - BOOL got_other = False; - canon_ace *pace_other = NULL; - canon_ace *pace_group = NULL; - - for (pace = *pp_ace; pace; pace = pace->next) { - if (pace->type == SMB_ACL_USER_OBJ) { - - if (setting_acl) - apply_default_perms(fsp, pace, S_IRUSR); - got_user = True; - - } else if (pace->type == SMB_ACL_GROUP_OBJ) { - - /* - * Ensure create mask/force create mode is respected on set. - */ - - if (setting_acl) - apply_default_perms(fsp, pace, S_IRGRP); - got_grp = True; - pace_group = pace; - - } else if (pace->type == SMB_ACL_OTHER) { - - /* - * Ensure create mask/force create mode is respected on set. - */ - - if (setting_acl) - apply_default_perms(fsp, pace, S_IROTH); - got_other = True; - pace_other = pace; - } - } - - if (!got_user) { - if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { - DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); - return False; - } - - ZERO_STRUCTP(pace); - pace->type = SMB_ACL_USER_OBJ; - pace->owner_type = UID_ACE; - pace->unix_ug.uid = pst->st_uid; - pace->trustee = *pfile_owner_sid; - pace->attr = ALLOW_ACE; - - if (setting_acl) { - /* If we only got an "everyone" perm, just use that. */ - if (!got_grp && got_other) - pace->perms = pace_other->perms; - else if (got_grp && uid_entry_in_group(pace, pace_group)) - pace->perms = pace_group->perms; - else - pace->perms = 0; - - apply_default_perms(fsp, pace, S_IRUSR); - } else { - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); - } - - DLIST_ADD(*pp_ace, pace); - } - - if (!got_grp) { - if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { - DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); - return False; - } - - ZERO_STRUCTP(pace); - pace->type = SMB_ACL_GROUP_OBJ; - pace->owner_type = GID_ACE; - pace->unix_ug.uid = pst->st_gid; - pace->trustee = *pfile_grp_sid; - pace->attr = ALLOW_ACE; - if (setting_acl) { - /* If we only got an "everyone" perm, just use that. */ - if (got_other) - pace->perms = pace_other->perms; - else - pace->perms = 0; - apply_default_perms(fsp, pace, S_IRGRP); - } else { - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); - } - - DLIST_ADD(*pp_ace, pace); - } - - if (!got_other) { - if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { - DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); - return False; - } - - ZERO_STRUCTP(pace); - pace->type = SMB_ACL_OTHER; - pace->owner_type = WORLD_ACE; - pace->unix_ug.world = -1; - pace->trustee = global_sid_World; - pace->attr = ALLOW_ACE; - if (setting_acl) { - pace->perms = 0; - apply_default_perms(fsp, pace, S_IROTH); - } else - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); - - DLIST_ADD(*pp_ace, pace); - } - - return True; -} - -/**************************************************************************** - Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries. - If it does not have them, check if there are any entries where the trustee is the - file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ. -****************************************************************************/ - -static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid) -{ - BOOL got_user_obj, got_group_obj; - canon_ace *current_ace; - int i, entries; - - entries = count_canon_ace_list(ace); - got_user_obj = False; - got_group_obj = False; - - for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) { - if (current_ace->type == SMB_ACL_USER_OBJ) - got_user_obj = True; - else if (current_ace->type == SMB_ACL_GROUP_OBJ) - got_group_obj = True; - } - if (got_user_obj && got_group_obj) { - DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n")); - return; - } - - for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) { - if (!got_user_obj && current_ace->owner_type == UID_ACE && - sid_equal(¤t_ace->trustee, pfile_owner_sid)) { - current_ace->type = SMB_ACL_USER_OBJ; - got_user_obj = True; - } - if (!got_group_obj && current_ace->owner_type == GID_ACE && - sid_equal(¤t_ace->trustee, pfile_grp_sid)) { - current_ace->type = SMB_ACL_GROUP_OBJ; - got_group_obj = True; - } - } - if (!got_user_obj) - DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n")); - if (!got_group_obj) - DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n")); -} - -/**************************************************************************** - Unpack a SEC_DESC into two canonical ace lists. -****************************************************************************/ - -static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, - DOM_SID *pfile_owner_sid, - DOM_SID *pfile_grp_sid, - canon_ace **ppfile_ace, canon_ace **ppdir_ace, - SEC_ACL *dacl) -{ - extern DOM_SID global_sid_Creator_Owner; - extern DOM_SID global_sid_Creator_Group; - extern DOM_SID global_sid_World; - extern struct generic_mapping file_generic_mapping; - BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False); - canon_ace *file_ace = NULL; - canon_ace *dir_ace = NULL; - canon_ace *tmp_ace = NULL; - canon_ace *current_ace = NULL; - BOOL got_dir_allow = False; - BOOL got_file_allow = False; - int i, j; - - *ppfile_ace = NULL; - *ppdir_ace = NULL; - - /* - * Convert the incoming ACL into a more regular form. - */ - - for(i = 0; i < dacl->num_aces; i++) { - SEC_ACE *psa = &dacl->ace[i]; - - if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) { - DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n")); - return False; - } - - if (nt4_compatible_acls()) { - /* - * The security mask may be UNIX_ACCESS_NONE which should map into - * no permissions (we overload the WRITE_OWNER bit for this) or it - * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this - * to be so. Any other bits override the UNIX_ACCESS_NONE bit. - */ - - /* - * Convert GENERIC bits to specific bits. - */ - - se_map_generic(&psa->info.mask, &file_generic_mapping); - - psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS); - - if(psa->info.mask != UNIX_ACCESS_NONE) - psa->info.mask &= ~UNIX_ACCESS_NONE; - } - } - - /* - * Deal with the fact that NT 4.x re-writes the canonical format - * that we return for default ACLs. If a directory ACE is identical - * to a inherited directory ACE then NT changes the bits so that the - * first ACE is set to OI|IO and the second ACE for this SID is set - * to CI. We need to repair this. JRA. - */ - - for(i = 0; i < dacl->num_aces; i++) { - SEC_ACE *psa1 = &dacl->ace[i]; - - for (j = i + 1; j < dacl->num_aces; j++) { - SEC_ACE *psa2 = &dacl->ace[j]; - - if (psa1->info.mask != psa2->info.mask) - continue; - - if (!sid_equal(&psa1->trustee, &psa2->trustee)) - continue; - - /* - * Ok - permission bits and SIDs are equal. - * Check if flags were re-written. - */ - - if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) { - - psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)); - psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT); - - } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) { - - psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)); - psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT); - - } - } - } - - for(i = 0; i < dacl->num_aces; i++) { - SEC_ACE *psa = &dacl->ace[i]; - - /* - * Ignore non-mappable SIDs (NT Authority, BUILTIN etc). - */ - - 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->trustee) )); - continue; - } - - /* - * Create a cannon_ace entry representing this NT DACL ACE. - */ - - if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - DEBUG(0,("create_canon_ace_lists: malloc fail.\n")); - return False; - } - - ZERO_STRUCTP(current_ace); - - 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. - * Note what kind of a POSIX ACL this should map to. - */ - - if( sid_equal(¤t_ace->trustee, &global_sid_World)) { - current_ace->owner_type = WORLD_ACE; - current_ace->unix_ug.world = -1; - current_ace->type = SMB_ACL_OTHER; - } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) { - current_ace->owner_type = UID_ACE; - current_ace->unix_ug.uid = pst->st_uid; - current_ace->type = SMB_ACL_USER_OBJ; - - /* - * The Creator Owner entry only specifies inheritable permissions, - * never access permissions. WinNT doesn't always set the ACE to - *INHERIT_ONLY, though. - */ - - if (nt4_compatible_acls()) - psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; - } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) { - current_ace->owner_type = GID_ACE; - current_ace->unix_ug.gid = pst->st_gid; - current_ace->type = SMB_ACL_GROUP_OBJ; - - /* - * The Creator Group entry only specifies inheritable permissions, - * never access permissions. WinNT doesn't always set the ACE to - *INHERIT_ONLY, though. - */ - if (nt4_compatible_acls()) - psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; - - } else if (NT_STATUS_IS_OK(sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid))) { - current_ace->owner_type = GID_ACE; - current_ace->type = SMB_ACL_GROUP; - } else if (NT_STATUS_IS_OK(sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid))) { - current_ace->owner_type = UID_ACE; - current_ace->type = SMB_ACL_USER; - } else { - fstring str; - - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n", - sid_to_string(str, ¤t_ace->trustee) )); - SAFE_FREE(current_ace); - return False; - } - - /* - * Map the given NT permissions into a UNIX mode_t containing only - * S_I(R|W|X)USR bits. - */ - - current_ace->perms |= map_nt_perms( psa->info, S_IRUSR); - current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE; - current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False); - - /* - * Now add the created ace to either the file list, the directory - * list, or both. We *MUST* preserve the order here (hence we use - * DLIST_ADD_END) as NT ACLs are order dependent. - */ - - if (fsp->is_directory) { - - /* - * We can only add to the default POSIX ACE list if the ACE is - * designed to be inherited by both files and directories. - */ - - if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) == - (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) { - - DLIST_ADD_END(dir_ace, current_ace, tmp_ace); - - /* - * Note if this was an allow ace. We can't process - * any further deny ace's after this. - */ - - if (current_ace->attr == ALLOW_ACE) - got_dir_allow = True; - - if ((current_ace->attr == DENY_ACE) && got_dir_allow) { - DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \ -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); - SAFE_FREE(current_ace); - return False; - } - - if( DEBUGLVL( 10 )) { - dbgtext("create_canon_ace_lists: adding dir ACL:\n"); - print_canon_ace( current_ace, 0); - } - - /* - * If this is not an inherit only ACE we need to add a duplicate - * to the file acl. - */ - - if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { - canon_ace *dup_ace = dup_canon_ace(current_ace); - - if (!dup_ace) { - DEBUG(0,("create_canon_ace_lists: malloc fail !\n")); - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - return False; - } - - /* - * We must not free current_ace here as its - * pointer is now owned by the dir_ace list. - */ - current_ace = dup_ace; - } else { - /* - * We must not free current_ace here as its - * pointer is now owned by the dir_ace list. - */ - current_ace = NULL; - } - } - } - - /* - * Only add to the file ACL if not inherit only. - */ - - if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { - DLIST_ADD_END(file_ace, current_ace, tmp_ace); - - /* - * Note if this was an allow ace. We can't process - * any further deny ace's after this. - */ - - if (current_ace->attr == ALLOW_ACE) - got_file_allow = True; - - if ((current_ace->attr == DENY_ACE) && got_file_allow) { - DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \ -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); - SAFE_FREE(current_ace); - return False; - } - - if( DEBUGLVL( 10 )) { - dbgtext("create_canon_ace_lists: adding file ACL:\n"); - print_canon_ace( current_ace, 0); - } - all_aces_are_inherit_only = False; - /* - * We must not free current_ace here as its - * pointer is now owned by the file_ace list. - */ - current_ace = NULL; - } - - /* - * Free if ACE was not added. - */ - - SAFE_FREE(current_ace); - } - - if (fsp->is_directory && all_aces_are_inherit_only) { - /* - * Windows 2000 is doing one of these weird 'inherit acl' - * traverses to conserve NTFS ACL resources. Just pretend - * there was no DACL sent. JRA. - */ - - DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n")); - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - file_ace = NULL; - dir_ace = NULL; - } else { - /* - * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each - * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP - * entries can be converted to *_OBJ. Usually we will already have these - * entries in the Default ACL, and the Access ACL will not have them. - */ - check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid); - check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid); - } - - *ppfile_ace = file_ace; - *ppdir_ace = dir_ace; - - return True; -} - -/**************************************************************************** - ASCII art time again... JRA :-). - - We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly, - we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW - entries). Secondly, the merge code has ensured that all duplicate SID entries for - allow or deny have been merged, so the same SID can only appear once in the deny - list or once in the allow list. - - We then process as follows : - - --------------------------------------------------------------------------- - First pass - look for a Everyone DENY entry. - - If it is deny all (rwx) trunate the list at this point. - Else, walk the list from this point and use the deny permissions of this - entry as a mask on all following allow entries. Finally, delete - the Everyone DENY entry (we have applied it to everything possible). - - In addition, in this pass we remove any DENY entries that have - no permissions (ie. they are a DENY nothing). - --------------------------------------------------------------------------- - Second pass - only deal with deny user entries. - - DENY user1 (perms XXX) - - new_perms = 0 - for all following allow group entries where user1 is in group - new_perms |= group_perms; - - user1 entry perms = new_perms & ~ XXX; - - Convert the deny entry to an allow entry with the new perms and - push to the end of the list. Note if the user was in no groups - this maps to a specific allow nothing entry for this user. - - The common case from the NT ACL choser (userX deny all) is - optimised so we don't do the group lookup - we just map to - an allow nothing entry. - - What we're doing here is inferring the allow permissions the - person setting the ACE on user1 wanted by looking at the allow - permissions on the groups the user is currently in. This will - be a snapshot, depending on group membership but is the best - we can do and has the advantage of failing closed rather than - open. - --------------------------------------------------------------------------- - Third pass - only deal with deny group entries. - - DENY group1 (perms XXX) - - for all following allow user entries where user is in group1 - user entry perms = user entry perms & ~ XXX; - - If there is a group Everyone allow entry with permissions YYY, - convert the group1 entry to an allow entry and modify its - permissions to be : - - new_perms = YYY & ~ XXX - - and push to the end of the list. - - If there is no group Everyone allow entry then convert the - group1 entry to a allow nothing entry and push to the end of the list. - - Note that the common case from the NT ACL choser (groupX deny all) - cannot be optimised here as we need to modify user entries who are - in the group to change them to a deny all also. - - What we're doing here is modifying the allow permissions of - user entries (which are more specific in POSIX ACLs) to mask - out the explicit deny set on the group they are in. This will - be a snapshot depending on current group membership but is the - best we can do and has the advantage of failing closed rather - than open. - --------------------------------------------------------------------------- - Fourth pass - cope with cumulative permissions. - - for all allow user entries, if there exists an allow group entry with - more permissive permissions, and the user is in that group, rewrite the - allow user permissions to contain both sets of permissions. - - Currently the code for this is #ifdef'ed out as these semantics make - no sense to me. JRA. - --------------------------------------------------------------------------- - - Note we *MUST* do the deny user pass first as this will convert deny user - entries into allow user entries which can then be processed by the deny - group pass. - - The above algorithm took a *lot* of thinking about - hence this - explaination :-). JRA. -****************************************************************************/ - -/**************************************************************************** - Process a canon_ace list entries. This is very complex code. We need - to go through and remove the "deny" permissions from any allow entry that matches - the id of this entry. We have already refused any NT ACL that wasn't in correct - order (DENY followed by ALLOW). If any allow entry ends up with zero permissions, - we just remove it (to fail safe). We have already removed any duplicate ace - entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all - allow entries. -****************************************************************************/ - -static void process_deny_list( canon_ace **pp_ace_list ) -{ - extern DOM_SID global_sid_World; - canon_ace *ace_list = *pp_ace_list; - canon_ace *curr_ace = NULL; - canon_ace *curr_ace_next = NULL; - - /* Pass 1 above - look for an Everyone, deny entry. */ - - for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { - canon_ace *allow_ace_p; - - curr_ace_next = curr_ace->next; /* So we can't lose the link. */ - - if (curr_ace->attr != DENY_ACE) - continue; - - if (curr_ace->perms == (mode_t)0) { - - /* Deny nothing entry - delete. */ - - DLIST_REMOVE(ace_list, curr_ace); - continue; - } - - if (!sid_equal(&curr_ace->trustee, &global_sid_World)) - continue; - - /* JRATEST - assert. */ - SMB_ASSERT(curr_ace->owner_type == WORLD_ACE); - - if (curr_ace->perms == ALL_ACE_PERMS) { - - /* - * Optimisation. This is a DENY_ALL to Everyone. Truncate the - * list at this point including this entry. - */ - - canon_ace *prev_entry = curr_ace->prev; - - free_canon_ace_list( curr_ace ); - if (prev_entry) - prev_entry->next = NULL; - else { - /* We deleted the entire list. */ - ace_list = NULL; - } - break; - } - - for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { - - /* - * Only mask off allow entries. - */ - - if (allow_ace_p->attr != ALLOW_ACE) - continue; - - allow_ace_p->perms &= ~curr_ace->perms; - } - - /* - * Now it's been applied, remove it. - */ - - DLIST_REMOVE(ace_list, curr_ace); - } - - /* Pass 2 above - deal with deny user entries. */ - - for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { - mode_t new_perms = (mode_t)0; - canon_ace *allow_ace_p; - canon_ace *tmp_ace; - - curr_ace_next = curr_ace->next; /* So we can't lose the link. */ - - if (curr_ace->attr != DENY_ACE) - continue; - - if (curr_ace->owner_type != UID_ACE) - continue; - - if (curr_ace->perms == ALL_ACE_PERMS) { - - /* - * Optimisation - this is a deny everything to this user. - * Convert to an allow nothing and push to the end of the list. - */ - - curr_ace->attr = ALLOW_ACE; - curr_ace->perms = (mode_t)0; - DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); - continue; - } - - for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { - - if (allow_ace_p->attr != ALLOW_ACE) - continue; - - /* We process GID_ACE and WORLD_ACE entries only. */ - - if (allow_ace_p->owner_type == UID_ACE) - continue; - - if (uid_entry_in_group( curr_ace, allow_ace_p)) - new_perms |= allow_ace_p->perms; - } - - /* - * Convert to a allow entry, modify the perms and push to the end - * of the list. - */ - - curr_ace->attr = ALLOW_ACE; - curr_ace->perms = (new_perms & ~curr_ace->perms); - DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); - } - - /* Pass 3 above - deal with deny group entries. */ - - for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { - canon_ace *tmp_ace; - canon_ace *allow_ace_p; - canon_ace *allow_everyone_p = NULL; - - curr_ace_next = curr_ace->next; /* So we can't lose the link. */ - - if (curr_ace->attr != DENY_ACE) - continue; - - if (curr_ace->owner_type != GID_ACE) - continue; - - for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { - - if (allow_ace_p->attr != ALLOW_ACE) - continue; - - /* Store a pointer to the Everyone allow, if it exists. */ - if (allow_ace_p->owner_type == WORLD_ACE) - allow_everyone_p = allow_ace_p; - - /* We process UID_ACE entries only. */ - - if (allow_ace_p->owner_type != UID_ACE) - continue; - - /* Mask off the deny group perms. */ - - if (uid_entry_in_group( allow_ace_p, curr_ace)) - allow_ace_p->perms &= ~curr_ace->perms; - } - - /* - * Convert the deny to an allow with the correct perms and - * push to the end of the list. - */ - - curr_ace->attr = ALLOW_ACE; - if (allow_everyone_p) - curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms; - else - curr_ace->perms = (mode_t)0; - DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); - - } - - /* Doing this fourth pass allows Windows semantics to be layered - * on top of POSIX semantics. I'm not sure if this is desirable. - * For example, in W2K ACLs there is no way to say, "Group X no - * access, user Y full access" if user Y is a member of group X. - * This seems completely broken semantics to me.... JRA. - */ - -#if 0 - /* Pass 4 above - deal with allow entries. */ - - for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { - canon_ace *allow_ace_p; - - curr_ace_next = curr_ace->next; /* So we can't lose the link. */ - - if (curr_ace->attr != ALLOW_ACE) - continue; - - if (curr_ace->owner_type != UID_ACE) - continue; - - for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) { - - if (allow_ace_p->attr != ALLOW_ACE) - continue; - - /* We process GID_ACE entries only. */ - - if (allow_ace_p->owner_type != GID_ACE) - continue; - - /* OR in the group perms. */ - - if (uid_entry_in_group( curr_ace, allow_ace_p)) - curr_ace->perms |= allow_ace_p->perms; - } - } -#endif - - *pp_ace_list = ace_list; -} - -/**************************************************************************** - Create a default mode that will be used if a security descriptor entry has - no user/group/world entries. -****************************************************************************/ - -static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode) -{ - int snum = SNUM(fsp->conn); - mode_t and_bits = (mode_t)0; - mode_t or_bits = (mode_t)0; - mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR; - - if (fsp->is_directory) - mode |= (S_IWUSR|S_IXUSR); - - /* - * Now AND with the create mode/directory mode bits then OR with the - * force create mode/force directory mode bits. - */ - - if (fsp->is_directory) { - and_bits = lp_dir_security_mask(snum); - or_bits = lp_force_dir_security_mode(snum); - } else { - and_bits = lp_security_mask(snum); - or_bits = lp_force_security_mode(snum); - } - - return ((mode & and_bits)|or_bits); -} - -/**************************************************************************** - Unpack a SEC_DESC into two canonical ace lists. We don't depend on this - succeeding. -****************************************************************************/ - -static BOOL unpack_canon_ace(files_struct *fsp, - SMB_STRUCT_STAT *pst, - DOM_SID *pfile_owner_sid, - DOM_SID *pfile_grp_sid, - canon_ace **ppfile_ace, canon_ace **ppdir_ace, - uint32 security_info_sent, SEC_DESC *psd) -{ - canon_ace *file_ace = NULL; - canon_ace *dir_ace = NULL; - - *ppfile_ace = NULL; - *ppdir_ace = NULL; - - if(security_info_sent == 0) { - DEBUG(0,("unpack_canon_ace: no security info sent !\n")); - return False; - } - - /* - * If no DACL then this is a chown only security descriptor. - */ - - if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl) - return True; - - /* - * Now go through the DACL and create the canon_ace lists. - */ - - if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid, - &file_ace, &dir_ace, psd->dacl)) - return False; - - if ((file_ace == NULL) && (dir_ace == NULL)) { - /* W2K traverse DACL set - ignore. */ - return True; - } - - /* - * Go through the canon_ace list and merge entries - * belonging to identical users of identical allow or deny type. - * We can do this as all deny entries come first, followed by - * all allow entries (we have mandated this before accepting this acl). - */ - - print_canon_ace_list( "file ace - before merge", file_ace); - merge_aces( &file_ace ); - - print_canon_ace_list( "dir ace - before merge", dir_ace); - merge_aces( &dir_ace ); - - /* - * NT ACLs are order dependent. Go through the acl lists and - * process DENY entries by masking the allow entries. - */ - - print_canon_ace_list( "file ace - before deny", file_ace); - process_deny_list( &file_ace); - - print_canon_ace_list( "dir ace - before deny", dir_ace); - process_deny_list( &dir_ace); - - /* - * A well formed POSIX file or default ACL has at least 3 entries, a - * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ - * and optionally a mask entry. Ensure this is the case. - */ - - print_canon_ace_list( "file ace - before valid", file_ace); - - /* - * A default 3 element mode entry for a file should be r-- --- ---. - * A default 3 element mode entry for a directory should be rwx --- ---. - */ - - pst->st_mode = create_default_mode(fsp, False); - - if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - return False; - } - - print_canon_ace_list( "dir ace - before valid", dir_ace); - - /* - * A default inheritable 3 element mode entry for a directory should be the - * mode Samba will use to create a file within. Ensure user rwx bits are set if - * it's a directory. - */ - - pst->st_mode = create_default_mode(fsp, True); - - if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - return False; - } - - print_canon_ace_list( "file ace - return", file_ace); - print_canon_ace_list( "dir ace - return", dir_ace); - - *ppfile_ace = file_ace; - *ppdir_ace = dir_ace; - return True; - -} - -/****************************************************************************** - When returning permissions, try and fit NT display - semantics if possible. Note the the canon_entries here must have been malloced. - The list format should be - first entry = owner, followed by group and other user - entries, last entry = other. - - Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries - are not ordered, and match on the most specific entry rather than walking a list, - then a simple POSIX permission of rw-r--r-- should really map to 5 entries, - - Entry 0: owner : deny all except read and write. - Entry 1: group : deny all except read. - Entry 2: owner : allow read and write. - Entry 3: group : allow read. - Entry 4: Everyone : allow read. - - But NT cannot display this in their ACL editor ! -********************************************************************************/ - -static void arrange_posix_perms( char *filename, canon_ace **pp_list_head) -{ - canon_ace *list_head = *pp_list_head; - canon_ace *owner_ace = NULL; - canon_ace *other_ace = NULL; - canon_ace *ace = NULL; - - for (ace = list_head; ace; ace = ace->next) { - if (ace->type == SMB_ACL_USER_OBJ) - owner_ace = ace; - else if (ace->type == SMB_ACL_OTHER) { - /* Last ace - this is "other" */ - other_ace = ace; - } - } - - if (!owner_ace || !other_ace) { - DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n", - filename )); - return; - } - - /* - * The POSIX algorithm applies to owner first, and other last, - * so ensure they are arranged in this order. - */ - - if (owner_ace) { - DLIST_PROMOTE(list_head, owner_ace); - } - - if (other_ace) { - DLIST_DEMOTE(list_head, other_ace, ace); - } - - /* We have probably changed the head of the list. */ - - *pp_list_head = list_head; -} - -/**************************************************************************** - Create a linked list of canonical ACE entries. -****************************************************************************/ - -static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, - DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type) -{ - extern DOM_SID global_sid_World; - connection_struct *conn = fsp->conn; - mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR); - canon_ace *list_head = NULL; - canon_ace *ace = NULL; - canon_ace *next_ace = NULL; - int entry_id = SMB_ACL_FIRST_ENTRY; - SMB_ACL_ENTRY_T entry; - size_t ace_count; - - while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) { - SMB_ACL_TAG_T tagtype; - SMB_ACL_PERMSET_T permset; - DOM_SID sid; - posix_id unix_ug; - enum ace_owner owner_type; - - /* get_next... */ - if (entry_id == SMB_ACL_FIRST_ENTRY) - entry_id = SMB_ACL_NEXT_ENTRY; - - /* Is this a MASK entry ? */ - if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) - continue; - - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) - continue; - - /* Decide which SID to use based on the ACL type. */ - switch(tagtype) { - case SMB_ACL_USER_OBJ: - /* Get the SID from the owner. */ - sid_copy(&sid, powner); - unix_ug.uid = psbuf->st_uid; - owner_type = UID_ACE; - break; - case SMB_ACL_USER: - { - uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); - if (puid == NULL) { - DEBUG(0,("canonicalise_acl: Failed to get uid.\n")); - continue; - } - /* - * A SMB_ACL_USER entry for the owner is shadowed by the - * SMB_ACL_USER_OBJ entry and Windows also cannot represent - * that entry, so we ignore it. We also don't create such - * entries out of the blue when setting ACLs, so a get/set - * cycle will drop them. - */ - if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) - continue; - uid_to_sid( &sid, *puid); - unix_ug.uid = *puid; - owner_type = UID_ACE; - SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); - break; - } - case SMB_ACL_GROUP_OBJ: - /* Get the SID from the owning group. */ - sid_copy(&sid, pgroup); - unix_ug.gid = psbuf->st_gid; - owner_type = GID_ACE; - break; - case SMB_ACL_GROUP: - { - gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); - if (pgid == NULL) { - DEBUG(0,("canonicalise_acl: Failed to get gid.\n")); - continue; - } - gid_to_sid( &sid, *pgid); - unix_ug.gid = *pgid; - owner_type = GID_ACE; - SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype); - break; - } - case SMB_ACL_MASK: - acl_mask = convert_permset_to_mode_t(conn, permset); - continue; /* Don't count the mask as an entry. */ - case SMB_ACL_OTHER: - /* Use the Everyone SID */ - sid = global_sid_World; - unix_ug.world = -1; - owner_type = WORLD_ACE; - break; - default: - DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype)); - continue; - } - - /* - * Add this entry to the list. - */ - - if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) - goto fail; - - ZERO_STRUCTP(ace); - ace->type = tagtype; - ace->perms = convert_permset_to_mode_t(conn, permset); - ace->attr = ALLOW_ACE; - ace->trustee = sid; - ace->unix_ug = unix_ug; - ace->owner_type = owner_type; - ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT)); - - DLIST_ADD(list_head, ace); - } - - /* - * This next call will ensure we have at least a user/group/world set. - */ - - if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False)) - goto fail; - - /* - * Now go through the list, masking the permissions with the - * acl_mask. Ensure all DENY Entries are at the start of the list. - */ - - DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" )); - - for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) { - next_ace = ace->next; - - /* Masks are only applied to entries other than USER_OBJ and OTHER. */ - if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ) - ace->perms &= acl_mask; - - if (ace->perms == 0) { - DLIST_PROMOTE(list_head, ace); - } - - if( DEBUGLVL( 10 ) ) { - print_canon_ace(ace, ace_count); - } - } - - arrange_posix_perms(fsp->fsp_name,&list_head ); - - print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head ); - - return list_head; - - fail: - - free_canon_ace_list(list_head); - return NULL; -} - -/**************************************************************************** - Attempt to apply an ACL to a file or directory. -****************************************************************************/ - -static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support) -{ - connection_struct *conn = fsp->conn; - BOOL ret = False; - SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1); - canon_ace *p_ace; - int i; - SMB_ACL_ENTRY_T mask_entry; - BOOL got_mask_entry = False; - SMB_ACL_PERMSET_T mask_permset; - SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS); - BOOL needs_mask = False; - mode_t mask_perms = 0; - -#if defined(POSIX_ACL_NEEDS_MASK) - /* HP-UX always wants to have a mask (called "class" there). */ - needs_mask = True; -#endif - - if (the_acl == NULL) { - - if (errno != ENOSYS) { - /* - * Only print this error message if we have some kind of ACL - * support that's not working. Otherwise we would always get this. - */ - DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n", - default_ace ? "default" : "file", strerror(errno) )); - } - *pacl_set_support = False; - return False; - } - - if( DEBUGLVL( 10 )) { - dbgtext("set_canon_ace_list: setting ACL:\n"); - for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) { - print_canon_ace( p_ace, i); - } - } - - for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) { - SMB_ACL_ENTRY_T the_entry; - SMB_ACL_PERMSET_T the_permset; - - /* - * ACLs only "need" an ACL_MASK entry if there are any named user or - * named group entries. But if there is an ACL_MASK entry, it applies - * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask - * so that it doesn't deny (i.e., mask off) any permissions. - */ - - if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) { - needs_mask = True; - mask_perms |= p_ace->perms; - } else if (p_ace->type == SMB_ACL_GROUP_OBJ) { - mask_perms |= p_ace->perms; - } - - /* - * Get the entry for this ACE. - */ - - if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n", - i, strerror(errno) )); - goto done; - } - - if (p_ace->type == SMB_ACL_MASK) { - mask_entry = the_entry; - got_mask_entry = True; - } - - /* - * Ok - we now know the ACL calls should be working, don't - * allow fallback to chmod. - */ - - *pacl_set_support = True; - - /* - * Initialise the entry from the canon_ace. - */ - - /* - * First tell the entry what type of ACE this is. - */ - - if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n", - i, strerror(errno) )); - goto done; - } - - /* - * Only set the qualifier (user or group id) if the entry is a user - * or group id ACE. - */ - - if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) { - if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n", - i, strerror(errno) )); - goto done; - } - } - - /* - * Convert the mode_t perms in the canon_ace to a POSIX permset. - */ - - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n", - i, strerror(errno) )); - goto done; - } - - if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n", - (unsigned int)p_ace->perms, i, strerror(errno) )); - goto done; - } - - /* - * ..and apply them to the entry. - */ - - if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n", - i, strerror(errno) )); - goto done; - } - - if( DEBUGLVL( 10 )) - print_canon_ace( p_ace, i); - - } - - if (needs_mask && !got_mask_entry) { - if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) )); - goto done; - } - - if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) )); - goto done; - } - - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) )); - goto done; - } - - if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) )); - goto done; - } - - if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) { - DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) )); - goto done; - } - } - - /* - * Check if the ACL is valid. - */ - - if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) { - DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n", - the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", - strerror(errno) )); - goto done; - } - - /* - * Finally apply it to the file or directory. - */ - - if(default_ace || fsp->is_directory || fsp->fd == -1) { - if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, 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; - -#ifdef ENOTSUP - if (errno == ENOTSUP) - *pacl_set_support = False; -#endif - - 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) )); - goto done; - } - } else { - if (SMB_VFS_SYS_ACL_SET_FD(fsp, 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; - -#ifdef ENOTSUP - if (errno == ENOTSUP) - *pacl_set_support = False; -#endif - - DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n", - fsp->fsp_name, strerror(errno) )); - goto done; - } - } - - ret = True; - - done: - - if (the_acl != NULL) - SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); - - return ret; -} - -/**************************************************************************** - Find a particular canon_ace entry. -****************************************************************************/ - -static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id) -{ - while (list) { - if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) || - (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) || - (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid))) - break; - list = list->next; - } - return list; -} - -/**************************************************************************** - -****************************************************************************/ - -SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl) -{ - SMB_ACL_ENTRY_T entry; - - if (!the_acl) - return NULL; - if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) { - SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); - return NULL; - } - return the_acl; -} - -/**************************************************************************** - Convert a canon_ace to a generic 3 element permission - if possible. -****************************************************************************/ - -#define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 ) - -static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms) -{ - int snum = SNUM(fsp->conn); - size_t ace_count = count_canon_ace_list(file_ace_list); - canon_ace *ace_p; - canon_ace *owner_ace = NULL; - canon_ace *group_ace = NULL; - canon_ace *other_ace = NULL; - mode_t and_bits; - mode_t or_bits; - - if (ace_count != 3) { - DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \ -posix perms.\n", fsp->fsp_name )); - return False; - } - - for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) { - if (ace_p->owner_type == UID_ACE) - owner_ace = ace_p; - else if (ace_p->owner_type == GID_ACE) - group_ace = ace_p; - else if (ace_p->owner_type == WORLD_ACE) - other_ace = ace_p; - } - - if (!owner_ace || !group_ace || !other_ace) { - DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n", - fsp->fsp_name )); - return False; - } - - *posix_perms = (mode_t)0; - - *posix_perms |= owner_ace->perms; - *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP); - *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP); - *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP); - *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH); - *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH); - *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH); - - /* The owner must have at least read access. */ - - *posix_perms |= S_IRUSR; - if (fsp->is_directory) - *posix_perms |= (S_IWUSR|S_IXUSR); - - /* If requested apply the masks. */ - - /* Get the initial bits to apply. */ - - if (fsp->is_directory) { - and_bits = lp_dir_security_mask(snum); - or_bits = lp_force_dir_security_mode(snum); - } else { - and_bits = lp_security_mask(snum); - or_bits = lp_force_security_mode(snum); - } - - *posix_perms = (((*posix_perms) & and_bits)|or_bits); - - DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n", - (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms, - fsp->fsp_name )); - - return True; -} - -/**************************************************************************** - Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and - a normal POSIX acl. Win2k needs these split acls re-merging into one ACL - with CI|OI set so it is inherited and also applies to the directory. - Based on code from "Jim McDonough" <jmcd@us.ibm.com>. -****************************************************************************/ - -static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) -{ - size_t i, j; - - for (i = 0; i < num_aces; i++) { - for (j = i+1; j < num_aces; j++) { - uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE); - uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE); - BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; - BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; - - /* We know the lower number ACE's are file entries. */ - if ((nt_ace_list[i].type == nt_ace_list[j].type) && - (nt_ace_list[i].size == nt_ace_list[j].size) && - (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) && - sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) && - (i_inh == j_inh) && - (i_flags_ni == 0) && - (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT| - SEC_ACE_FLAG_CONTAINER_INHERIT| - SEC_ACE_FLAG_INHERIT_ONLY))) { - /* - * W2K wants to have access allowed zero access ACE's - * at the end of the list. If the mask is zero, merge - * the non-inherited ACE onto the inherited ACE. - */ - - if (nt_ace_list[i].info.mask == 0) { - nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| - (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0); - if (num_aces - i - 1 > 0) - memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) * - sizeof(SEC_ACE)); - - DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n", - (unsigned int)i, (unsigned int)j )); - } else { - /* - * These are identical except for the flags. - * Merge the inherited ACE onto the non-inherited ACE. - */ - - nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| - (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0); - if (num_aces - j - 1 > 0) - memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) * - sizeof(SEC_ACE)); - - DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n", - (unsigned int)j, (unsigned int)i )); - } - num_aces--; - break; - } - } - } - - return num_aces; -} -/**************************************************************************** - Reply to query a security descriptor from an fsp. If it succeeds it allocates - the space for the return elements and returns the size needed to return the - security descriptor. This should be the only external function needed for - the UNIX style get ACL. -****************************************************************************/ - -size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) -{ - extern DOM_SID global_sid_Builtin_Administrators; - extern DOM_SID global_sid_Builtin_Users; - extern DOM_SID global_sid_Creator_Owner; - extern DOM_SID global_sid_Creator_Group; - connection_struct *conn = fsp->conn; - SMB_STRUCT_STAT sbuf; - SEC_ACE *nt_ace_list = NULL; - DOM_SID owner_sid; - DOM_SID group_sid; - size_t sd_size = 0; - SEC_ACL *psa = NULL; - size_t num_acls = 0; - size_t num_dir_acls = 0; - size_t num_aces = 0; - SMB_ACL_T posix_acl = NULL; - SMB_ACL_T dir_acl = NULL; - canon_ace *file_ace = NULL; - canon_ace *dir_ace = NULL; - size_t num_profile_acls = 0; - struct pai_val *pal = NULL; - SEC_DESC *psd = NULL; - - *ppdesc = NULL; - - DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name )); - - if(fsp->is_directory || fsp->fd == -1) { - - /* Get the stat struct for the owner info. */ - if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { - return 0; - } - /* - * Get the ACL from the path. - */ - - posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS); - - /* - * If it's a directory get the default POSIX ACL. - */ - - if(fsp->is_directory) { - dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); - dir_acl = free_empty_sys_acl(conn, dir_acl); - } - - } else { - - /* Get the stat struct for the owner info. */ - if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { - return 0; - } - /* - * Get the ACL from the fd. - */ - posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); - } - - DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n", - posix_acl ? "present" : "absent", - dir_acl ? "present" : "absent" )); - - pal = load_inherited_info(fsp); - - /* - * Get the owner, group and world SIDs. - */ - - if (lp_profile_acls(SNUM(fsp->conn))) { - /* For WXP SP1 the owner must be administrators. */ - sid_copy(&owner_sid, &global_sid_Builtin_Administrators); - sid_copy(&group_sid, &global_sid_Builtin_Users); - num_profile_acls = 2; - } else { - create_file_sids(&sbuf, &owner_sid, &group_sid); - } - - if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) { - - /* - * In the optimum case Creator Owner and Creator Group would be used for - * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this - * would lead to usability problems under Windows: The Creator entries - * are only available in browse lists of directories and not for files; - * additionally the identity of the owning group couldn't be determined. - * We therefore use those identities only for Default ACLs. - */ - - /* Create the canon_ace lists. */ - file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS ); - - /* We must have *some* ACLS. */ - - if (count_canon_ace_list(file_ace) == 0) { - DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name )); - return 0; - } - - if (fsp->is_directory && dir_acl) { - dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, - &global_sid_Creator_Owner, - &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT ); - } - - /* - * Create the NT ACE list from the canonical ace lists. - */ - - { - canon_ace *ace; - int nt_acl_type; - int i; - - if (nt4_compatible_acls() && dir_ace) { - /* - * NT 4 chokes if an ACL contains an INHERIT_ONLY entry - * but no non-INHERIT_ONLY entry for one SID. So we only - * remove entries from the Access ACL if the - * corresponding Default ACL entries have also been - * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP - * are exceptions. We can do nothing - * intelligent if the Default ACL contains entries that - * are not also contained in the Access ACL, so this - * case will still fail under NT 4. - */ - - ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(dir_ace, ace); - SAFE_FREE(ace); - - ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(file_ace, ace); - SAFE_FREE(ace); - } - } - - /* - * WinNT doesn't usually have Creator Group - * in browse lists, so we send this entry to - * WinNT even if it contains no relevant - * permissions. Once we can add - * Creator Group to browse lists we can - * re-enable this. - */ - -#if 0 - ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(dir_ace, ace); - SAFE_FREE(ace); - } -#endif - - ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(file_ace, ace); - SAFE_FREE(ace); - } - } - - num_acls = count_canon_ace_list(file_ace); - num_dir_acls = count_canon_ace_list(dir_ace); - - /* Allocate the ace list. */ - if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) { - DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n")); - goto done; - } - - memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) ); - - /* - * Create the NT ACE list from the canonical ace lists. - */ - - ace = file_ace; - - for (i = 0; i < num_acls; i++, ace = ace->next) { - SEC_ACCESS acc; - - acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); - init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0); - } - - /* The User must have access to a profile share - even if we can't map the SID. */ - if (lp_profile_acls(SNUM(fsp->conn))) { - SEC_ACCESS acc; - - init_sec_access(&acc,FILE_GENERIC_ALL); - init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, - acc, 0); - } - - ace = dir_ace; - - for (i = 0; i < num_dir_acls; i++, ace = ace->next) { - SEC_ACCESS acc; - - acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); - 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| - (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0)); - } - - /* The User must have access to a profile share - even if we can't map the SID. */ - if (lp_profile_acls(SNUM(fsp->conn))) { - SEC_ACCESS acc; - - init_sec_access(&acc,FILE_GENERIC_ALL); - init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, - SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| - SEC_ACE_FLAG_INHERIT_ONLY|0); - } - - /* - * Merge POSIX default ACLs and normal ACLs into one NT ACE. - * Win2K needs this to get the inheritance correct when replacing ACLs - * on a directory tree. Based on work by Jim @ IBM. - */ - - num_aces = merge_default_aces(nt_ace_list, num_aces); - - } - - if (num_aces) { - if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) { - DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); - goto done; - } - } - } /* security_info & DACL_SECURITY_INFORMATION */ - - psd = make_standard_sec_desc( main_loop_talloc_get(), - (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL, - (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL, - psa, - &sd_size); - - if(!psd) { - DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n")); - sd_size = 0; - } else { - /* - * Windows 2000: The DACL_PROTECTED flag in the security - * descriptor marks the ACL as non-inheriting, i.e., no - * ACEs from higher level directories propagate to this - * ACL. In the POSIX ACL model permissions are only - * inherited at file create time, so ACLs never contain - * any ACEs that are inherited dynamically. The DACL_PROTECTED - * flag doesn't seem to bother Windows NT. - */ - if (get_protected_flag(pal)) - psd->type |= SE_DESC_DACL_PROTECTED; - } - - if (psd->dacl) - dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces); - - *ppdesc = psd; - - done: - - if (posix_acl) - SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); - if (dir_acl) - SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl); - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - free_inherited_info(pal); - SAFE_FREE(nt_ace_list); - - return sd_size; -} - -/**************************************************************************** - Try to chown a file. We will be able to chown it under the following conditions. - - 1) If we have root privileges, then it will just work. - 2) If we have write permission to the file and dos_filemodes is set - then allow chown to the currently authenticated user. -****************************************************************************/ - -static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) -{ - int ret; - extern struct current_user current_user; - files_struct *fsp; - SMB_STRUCT_STAT st; - - /* try the direct way first */ - ret = SMB_VFS_CHOWN(conn, fname, uid, gid); - if (ret == 0) - return 0; - - if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) - return -1; - - if (SMB_VFS_STAT(conn,fname,&st)) - return -1; - - fsp = open_file_fchmod(conn,fname,&st); - if (!fsp) - return -1; - - /* only allow chown to the current user. This is more secure, - and also copes with the case where the SID in a take ownership ACL is - a local SID on the users workstation - */ - uid = current_user.uid; - - become_root(); - /* Keep the current file gid the same. */ - ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1); - unbecome_root(); - - close_file_fchmod(fsp); - - return ret; -} - -/**************************************************************************** - Reply to set a security descriptor on an fsp. security_info_sent is the - description of the following NT ACL. - This should be the only external function needed for the UNIX style set ACL. -****************************************************************************/ - -BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) -{ - connection_struct *conn = fsp->conn; - uid_t user = (uid_t)-1; - gid_t grp = (gid_t)-1; - SMB_STRUCT_STAT sbuf; - DOM_SID file_owner_sid; - DOM_SID file_grp_sid; - canon_ace *file_ace_list = NULL; - canon_ace *dir_ace_list = NULL; - BOOL acl_perms = False; - mode_t orig_mode = (mode_t)0; - uid_t orig_uid; - gid_t orig_gid; - BOOL need_chown = False; - extern struct current_user current_user; - - DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name )); - - if (!CAN_WRITE(conn)) { - DEBUG(10,("set acl rejected on read-only share\n")); - return False; - } - - /* - * Get the current state of the file. - */ - - if(fsp->is_directory || fsp->fd == -1) { - if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) - return False; - } else { - if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) - return False; - } - - /* Save the original elements we check against. */ - orig_mode = sbuf.st_mode; - orig_uid = sbuf.st_uid; - orig_gid = sbuf.st_gid; - - /* - * Unpack the user/group/world id's. - */ - - if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd)) - return False; - - /* - * Do we need to chown ? - */ - - if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) - need_chown = True; - - /* - * Chown before setting ACL only if we don't change the user, or - * if we change to the current user, but not if we want to give away - * the file. - */ - - if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) { - - DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); - - if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { - DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); - return False; - } - - /* - * Recheck the current state of the file, which may have changed. - * (suid/sgid bits, for instance) - */ - - if(fsp->is_directory) { - if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) { - return False; - } - } else { - - int ret; - - if(fsp->fd == -1) - ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); - else - ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf); - - if(ret != 0) - return False; - } - - /* Save the original elements we check against. */ - orig_mode = sbuf.st_mode; - orig_uid = sbuf.st_uid; - orig_gid = sbuf.st_gid; - - /* We did it, don't try again */ - need_chown = False; - } - - create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); - - acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, - &file_ace_list, &dir_ace_list, security_info_sent, psd); - - /* Ignore W2K traverse DACL set. */ - if (file_ace_list || dir_ace_list) { - - if (!acl_perms) { - DEBUG(3,("set_nt_acl: cannot set permissions\n")); - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - return False; - } - - /* - * Only change security if we got a DACL. - */ - - if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) { - - BOOL acl_set_support = False; - BOOL ret = False; - - /* - * Try using the POSIX ACL set first. Fall back to chmod if - * we have no ACL support on this filesystem. - */ - - if (acl_perms && file_ace_list) { - ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support); - if (acl_set_support && ret == False) { - DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) )); - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - return False; - } - } - - if (acl_perms && acl_set_support && fsp->is_directory) { - if (dir_ace_list) { - if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) { - DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) )); - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - return False; - } - } else { - - /* - * No default ACL - delete one if it exists. - */ - - if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) { - DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno))); - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - return False; - } - } - } - - if (acl_set_support) - store_inheritance_attributes(fsp, file_ace_list, dir_ace_list, - (psd->type & SE_DESC_DACL_PROTECTED) ? True : False); - - /* - * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod. - */ - - if(!acl_set_support && acl_perms) { - mode_t posix_perms; - - if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) { - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n", - fsp->fsp_name )); - return False; - } - - if (orig_mode != posix_perms) { - - DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n", - fsp->fsp_name, (unsigned int)posix_perms )); - - if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) { - DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) )); - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - return False; - } - } - } - } - - free_canon_ace_list(file_ace_list); - free_canon_ace_list(dir_ace_list); - } - - /* Any chown pending? */ - if (need_chown) { - - DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); - - if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { - DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); - return False; - } - } - - return True; -} - -/**************************************************************************** - Get the actual group bits stored on a file with an ACL. Has no effect if - the file has no ACL. Needed in dosmode code where the stat() will return - the mask bits, not the real group bits, for a file with an ACL. -****************************************************************************/ - -int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode ) -{ - int entry_id = SMB_ACL_FIRST_ENTRY; - SMB_ACL_ENTRY_T entry; - SMB_ACL_T posix_acl; - - posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS); - if (posix_acl == (SMB_ACL_T)NULL) - return -1; - - while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { - SMB_ACL_TAG_T tagtype; - SMB_ACL_PERMSET_T permset; - - /* get_next... */ - if (entry_id == SMB_ACL_FIRST_ENTRY) - entry_id = SMB_ACL_NEXT_ENTRY; - - if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1) - return -1; - - if (tagtype == SMB_ACL_GROUP_OBJ) { - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { - return -1; - } else { - *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP); - *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0); - *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0); - *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0); - return 0;; - } - } - } - return -1; -} - -/**************************************************************************** - Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL - and set the mask to rwx. Needed to preserve complex ACLs set by NT. -****************************************************************************/ - -static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode) -{ - int entry_id = SMB_ACL_FIRST_ENTRY; - SMB_ACL_ENTRY_T entry; - int num_entries = 0; - - while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { - SMB_ACL_TAG_T tagtype; - SMB_ACL_PERMSET_T permset; - mode_t perms; - - /* get_next... */ - if (entry_id == SMB_ACL_FIRST_ENTRY) - entry_id = SMB_ACL_NEXT_ENTRY; - - if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) - return -1; - - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) - return -1; - - num_entries++; - - switch(tagtype) { - case SMB_ACL_USER_OBJ: - perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR); - break; - case SMB_ACL_GROUP_OBJ: - perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP); - break; - case SMB_ACL_MASK: - /* - * FIXME: The ACL_MASK entry permissions should really be set to - * the union of the permissions of all ACL_USER, - * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what - * acl_calc_mask() does, but Samba ACLs doesn't provide it. - */ - perms = S_IRUSR|S_IWUSR|S_IXUSR; - break; - case SMB_ACL_OTHER: - perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH); - break; - default: - continue; - } - - if (map_acl_perms_to_permset(conn, perms, &permset) == -1) - return -1; - - if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1) - return -1; - } - - /* - * If this is a simple 3 element ACL or no elements then it's a standard - * UNIX permission set. Just use chmod... - */ - - if ((num_entries == 3) || (num_entries == 0)) - return -1; - - return 0; -} - -/**************************************************************************** - Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ, - GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the - resulting ACL on TO. Note that name is in UNIX character set. -****************************************************************************/ - -static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode) -{ - SMB_ACL_T posix_acl = NULL; - int ret = -1; - - if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL) - return -1; - - if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) - goto done; - - ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl); - - done: - - SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); - return ret; -} - -/**************************************************************************** - Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL - and set the mask to rwx. Needed to preserve complex ACLs set by NT. - Note that name is in UNIX character set. -****************************************************************************/ - -int chmod_acl(connection_struct *conn, const char *name, mode_t mode) -{ - return copy_access_acl(conn, name, name, mode); -} - -/**************************************************************************** - If "inherit permissions" is set and the parent directory has no default - ACL but it does have an Access ACL, inherit this Access ACL to file name. -****************************************************************************/ - -int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode) -{ - pstring dirname; - pstrcpy(dirname, parent_dirname(name)); - - if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname)) - return 0; - - return copy_access_acl(conn, dirname, name, mode); -} - -/**************************************************************************** - Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL - and set the mask to rwx. Needed to preserve complex ACLs set by NT. -****************************************************************************/ - -int fchmod_acl(files_struct *fsp, int fd, mode_t mode) -{ - connection_struct *conn = fsp->conn; - SMB_ACL_T posix_acl = NULL; - int ret = -1; - - if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL) - return -1; - - if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) - goto done; - - ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl); - - done: - - SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); - return ret; -} - -/**************************************************************************** - Check for an existing default POSIX ACL on a directory. -****************************************************************************/ - -BOOL directory_has_default_acl(connection_struct *conn, const char *fname) -{ - SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT); - BOOL has_acl = False; - SMB_ACL_ENTRY_T entry; - - if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) - has_acl = True; - - if (dir_acl) - SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl); - return has_acl; -} diff --git a/source/smbd/process.c b/source/smbd/process.c index 718d1bb67b2..592a0efc990 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. process incoming packets - main loop - Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Andrew Tridgell 1992-2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> 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 @@ -20,1348 +21,76 @@ #include "includes.h" -struct timeval smb_last_time; - -static char *InBuffer = NULL; -char *OutBuffer = NULL; -char *last_inbuf = NULL; - -/* - * Size of data we can send to client. Set - * by the client for all protocols above CORE. - * Set by us for CORE protocol. - */ -int max_send = BUFFER_SIZE; /* - * Size of the data we can receive. Set by us. - * Can be modified by the max xmit parameter. + * initialize an smb process */ -int max_recv = BUFFER_SIZE; - -extern int last_message; -extern int global_oplock_break; -extern userdom_struct current_user_info; -extern int smb_read_error; -SIG_ATOMIC_T reload_after_sighup = 0; -SIG_ATOMIC_T got_sig_term = 0; -BOOL global_machine_password_needs_changing = False; -extern int max_send; - -/**************************************************************************** - Function to return the current request mid from Inbuffer. -****************************************************************************/ - -uint16 get_current_mid(void) -{ - return SVAL(InBuffer,smb_mid); -} - -/**************************************************************************** - structure to hold a linked list of queued messages. - for processing. -****************************************************************************/ - -typedef struct { - ubi_slNode msg_next; - char *msg_buf; - int msg_len; -} pending_message_list; - -static ubi_slList smb_oplock_queue = { NULL, (ubi_slNodePtr)&smb_oplock_queue, 0}; - -/**************************************************************************** - Function to push a message onto the tail of a linked list of smb messages ready - for processing. -****************************************************************************/ - -static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len) -{ - pending_message_list *msg = (pending_message_list *) - malloc(sizeof(pending_message_list)); - - if(msg == NULL) { - DEBUG(0,("push_message: malloc fail (1)\n")); - return False; - } - - msg->msg_buf = (char *)malloc(msg_len); - if(msg->msg_buf == NULL) { - DEBUG(0,("push_message: malloc fail (2)\n")); - SAFE_FREE(msg); - return False; - } - - memcpy(msg->msg_buf, buf, msg_len); - msg->msg_len = msg_len; - - ubi_slAddTail( list_head, msg); - - /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(buf,smb_mid)); - - return True; -} - -/**************************************************************************** - Function to push a smb message onto a linked list of local smb messages ready - for processing. -****************************************************************************/ - -BOOL push_oplock_pending_smb_message(char *buf, int msg_len) -{ - return push_message(&smb_oplock_queue, buf, msg_len); -} - -/**************************************************************************** - Do all async processing in here. This includes UDB oplock messages, kernel - oplock messages, change notify events etc. -****************************************************************************/ - -static void async_processing(char *buffer, int buffer_len) -{ - DEBUG(10,("async_processing: Doing async processing.\n")); - - /* check for oplock messages (both UDP and kernel) */ - if (receive_local_message(buffer, buffer_len, 1)) { - process_local_message(buffer, buffer_len); - } - - if (got_sig_term) { - exit_server("Caught TERM signal"); - } - - /* check for async change notify events */ - process_pending_change_notify_queue(0); - - /* check for sighup processing */ - if (reload_after_sighup) { - change_to_root_user(); - DEBUG(1,("Reloading services after SIGHUP\n")); - reload_services(False); - reload_after_sighup = 0; - } -} - -/**************************************************************************** - Do a select on an two fd's - with timeout. - - If a local udp message has been pushed onto the - queue (this can only happen during oplock break - processing) call async_processing() - - If a pending smb message has been pushed onto the - queue (this can only happen during oplock break - processing) return this next. - - If the first smbfd is ready then read an smb from it. - if the second (loopback UDP) fd is ready then read a message - from it and setup the buffer header to identify the length - and from address. - Returns False on timeout or error. - Else returns True. - -The timeout is in milliseconds -****************************************************************************/ - -static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) +void smbd_process_init(void) { - fd_set fds; - int selrtn; - struct timeval to; - int maxfd; - - smb_read_error = 0; - - again: - - /* - * Note that this call must be before processing any SMB - * messages as we need to synchronously process any messages - * we may have sent to ourselves from the previous SMB. - */ - message_dispatch(); - - /* - * Check to see if we already have a message on the smb queue. - * If so - copy and return it. - */ - if(ubi_slCount(&smb_oplock_queue) != 0) { - pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue); - memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); - - /* Free the message we just copied. */ - SAFE_FREE(msg->msg_buf); - SAFE_FREE(msg); - - DEBUG(5,("receive_message_or_smb: returning queued smb message.\n")); - return True; - } - - - /* - * Setup the select read fd set. - */ - - FD_ZERO(&fds); - - /* - * Ensure we process oplock break messages by preference. - * We have to do this before the select, after the select - * and if the select returns EINTR. This is due to the fact - * that the selects called from async_processing can eat an EINTR - * caused by a signal (we can't take the break message there). - * This is hideously complex - *MUST* be simplified for 3.0 ! JRA. - */ - - if (oplock_message_waiting(&fds)) { - DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n")); - async_processing(buffer, buffer_len); - /* - * After async processing we must go and do the select again, as - * the state of the flag in fds for the server file descriptor is - * indeterminate - we may have done I/O on it in the oplock processing. JRA. - */ - goto again; - } - - FD_SET(smbd_server_fd(),&fds); - maxfd = setup_oplock_select_set(&fds); - - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; - - 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 - is the best we can do until the oplock code knows more about - signals */ - if (selrtn == -1 && errno == EINTR) { - async_processing(buffer, buffer_len); - /* - * After async processing we must go and do the select again, as - * the state of the flag in fds for the server file descriptor is - * indeterminate - we may have done I/O on it in the oplock processing. JRA. - */ - goto again; - } - - /* 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; - } - - /* - * Ensure we process oplock break messages by preference. - * This is IMPORTANT ! Otherwise we can starve other processes - * sending us an oplock break message. JRA. - */ - - if (oplock_message_waiting(&fds)) { - async_processing(buffer, buffer_len); - /* - * After async processing we must go and do the select again, as - * the state of the flag in fds for the server file descriptor is - * indeterminate - we may have done I/O on it in the oplock processing. JRA. - */ - goto again; - } + TALLOC_CTX *mem_ctx; - return receive_smb(smbd_server_fd(), buffer, 0); -} - -/**************************************************************************** -Get the next SMB packet, doing the local message processing automatically. -****************************************************************************/ - -BOOL receive_next_smb(char *inbuf, int bufsize, int timeout) -{ - BOOL got_keepalive; - BOOL ret; - - do { - ret = receive_message_or_smb(inbuf,bufsize,timeout); - - got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive)); - } while (ret && got_keepalive); - - return ret; -} - -/**************************************************************************** - We're terminating and have closed all our files/connections etc. - If there are any pending local messages we need to respond to them - before termination so that other smbds don't think we just died whilst - holding oplocks. -****************************************************************************/ - -void respond_to_all_remaining_local_messages(void) -{ - char buffer[1024]; - - /* - * Assert we have no exclusive open oplocks. - */ - - if(get_number_of_exclusive_open_oplocks()) { - DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n", - get_number_of_exclusive_open_oplocks() )); - return; - } - - /* - * Keep doing receive_local_message with a 1 ms timeout until - * we have no more messages. - */ - - while(receive_local_message(buffer, sizeof(buffer), 1)) { - /* Deal with oplock break requests from other smbd's. */ - process_local_message(buffer, sizeof(buffer)); - } - - return; -} - - -/* -These flags determine some of the permissions required to do an operation - -Note that I don't set NEED_WRITE on some write operations because they -are used by some brain-dead clients when printing, and I don't want to -force write permissions on print services. -*/ -#define AS_USER (1<<0) -#define NEED_WRITE (1<<1) -#define TIME_INIT (1<<2) -#define CAN_IPC (1<<3) -#define AS_GUEST (1<<5) -#define QUEUE_IN_OPLOCK (1<<6) - -/* - define a list of possible SMB messages and their corresponding - functions. Any message that has a NULL function is unimplemented - - please feel free to contribute implementations! -*/ -static const struct smb_message_struct { - const char *name; - int (*fn)(connection_struct *conn, char *, char *, int, int); - int flags; -} smb_messages[256] = { - -/* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE}, -/* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE}, -/* 0x02 */ { "SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK }, -/* 0x03 */ { "SMBcreate",reply_mknew,AS_USER}, -/* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC }, -/* 0x05 */ { "SMBflush",reply_flush,AS_USER}, -/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK}, -/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK}, -/* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER}, -/* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE}, -/* 0x0a */ { "SMBread",reply_read,AS_USER}, -/* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC }, -/* 0x0c */ { "SMBlock",reply_lock,AS_USER}, -/* 0x0d */ { "SMBunlock",reply_unlock,AS_USER}, -/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK }, -/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, -/* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER}, -/* 0x11 */ { "SMBexit",reply_exit,0}, -/* 0x12 */ { "SMBlseek",reply_lseek,AS_USER}, -/* 0x13 */ { "SMBlockread",reply_lockread,AS_USER}, -/* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER}, -/* 0x15 */ { NULL, NULL, 0 }, -/* 0x16 */ { NULL, NULL, 0 }, -/* 0x17 */ { NULL, NULL, 0 }, -/* 0x18 */ { NULL, NULL, 0 }, -/* 0x19 */ { NULL, NULL, 0 }, -/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER}, -/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER}, -/* 0x1c */ { "SMBreadBs",NULL,0 }, -/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER}, -/* 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 }, -/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER }, -/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER }, -/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC }, -/* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC}, -/* 0x27 */ { "SMBioctl",reply_ioctl,0}, -/* 0x28 */ { "SMBioctls",NULL,AS_USER}, -/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK }, -/* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK }, -/* 0x2b */ { "SMBecho",reply_echo,0}, -/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER}, -/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK }, -/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC }, -/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC }, -/* 0x30 */ { NULL, NULL, 0 }, -/* 0x31 */ { NULL, NULL, 0 }, -/* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC }, -/* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER}, -/* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER}, -/* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER}, -/* 0x36 */ { NULL, NULL, 0 }, -/* 0x37 */ { NULL, NULL, 0 }, -/* 0x38 */ { NULL, NULL, 0 }, -/* 0x39 */ { NULL, NULL, 0 }, -/* 0x3a */ { NULL, NULL, 0 }, -/* 0x3b */ { NULL, NULL, 0 }, -/* 0x3c */ { NULL, NULL, 0 }, -/* 0x3d */ { NULL, NULL, 0 }, -/* 0x3e */ { NULL, NULL, 0 }, -/* 0x3f */ { NULL, NULL, 0 }, -/* 0x40 */ { NULL, NULL, 0 }, -/* 0x41 */ { NULL, NULL, 0 }, -/* 0x42 */ { NULL, NULL, 0 }, -/* 0x43 */ { NULL, NULL, 0 }, -/* 0x44 */ { NULL, NULL, 0 }, -/* 0x45 */ { NULL, NULL, 0 }, -/* 0x46 */ { NULL, NULL, 0 }, -/* 0x47 */ { NULL, NULL, 0 }, -/* 0x48 */ { NULL, NULL, 0 }, -/* 0x49 */ { NULL, NULL, 0 }, -/* 0x4a */ { NULL, NULL, 0 }, -/* 0x4b */ { NULL, NULL, 0 }, -/* 0x4c */ { NULL, NULL, 0 }, -/* 0x4d */ { NULL, NULL, 0 }, -/* 0x4e */ { NULL, NULL, 0 }, -/* 0x4f */ { NULL, NULL, 0 }, -/* 0x50 */ { NULL, NULL, 0 }, -/* 0x51 */ { NULL, NULL, 0 }, -/* 0x52 */ { NULL, NULL, 0 }, -/* 0x53 */ { NULL, NULL, 0 }, -/* 0x54 */ { NULL, NULL, 0 }, -/* 0x55 */ { NULL, NULL, 0 }, -/* 0x56 */ { NULL, NULL, 0 }, -/* 0x57 */ { NULL, NULL, 0 }, -/* 0x58 */ { NULL, NULL, 0 }, -/* 0x59 */ { NULL, NULL, 0 }, -/* 0x5a */ { NULL, NULL, 0 }, -/* 0x5b */ { NULL, NULL, 0 }, -/* 0x5c */ { NULL, NULL, 0 }, -/* 0x5d */ { NULL, NULL, 0 }, -/* 0x5e */ { NULL, NULL, 0 }, -/* 0x5f */ { NULL, NULL, 0 }, -/* 0x60 */ { NULL, NULL, 0 }, -/* 0x61 */ { NULL, NULL, 0 }, -/* 0x62 */ { NULL, NULL, 0 }, -/* 0x63 */ { NULL, NULL, 0 }, -/* 0x64 */ { NULL, NULL, 0 }, -/* 0x65 */ { NULL, NULL, 0 }, -/* 0x66 */ { NULL, NULL, 0 }, -/* 0x67 */ { NULL, NULL, 0 }, -/* 0x68 */ { NULL, NULL, 0 }, -/* 0x69 */ { NULL, NULL, 0 }, -/* 0x6a */ { NULL, NULL, 0 }, -/* 0x6b */ { NULL, NULL, 0 }, -/* 0x6c */ { NULL, NULL, 0 }, -/* 0x6d */ { NULL, NULL, 0 }, -/* 0x6e */ { NULL, NULL, 0 }, -/* 0x6f */ { NULL, NULL, 0 }, -/* 0x70 */ { "SMBtcon",reply_tcon,0}, -/* 0x71 */ { "SMBtdis",reply_tdis,0}, -/* 0x72 */ { "SMBnegprot",reply_negprot,0}, -/* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0}, -/* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */ -/* 0x75 */ { "SMBtconX",reply_tcon_and_X,0}, -/* 0x76 */ { NULL, NULL, 0 }, -/* 0x77 */ { NULL, NULL, 0 }, -/* 0x78 */ { NULL, NULL, 0 }, -/* 0x79 */ { NULL, NULL, 0 }, -/* 0x7a */ { NULL, NULL, 0 }, -/* 0x7b */ { NULL, NULL, 0 }, -/* 0x7c */ { NULL, NULL, 0 }, -/* 0x7d */ { NULL, NULL, 0 }, -/* 0x7e */ { NULL, NULL, 0 }, -/* 0x7f */ { NULL, NULL, 0 }, -/* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER}, -/* 0x81 */ { "SMBsearch",reply_search,AS_USER}, -/* 0x82 */ { "SMBffirst",reply_search,AS_USER}, -/* 0x83 */ { "SMBfunique",reply_search,AS_USER}, -/* 0x84 */ { "SMBfclose",reply_fclose,AS_USER}, -/* 0x85 */ { NULL, NULL, 0 }, -/* 0x86 */ { NULL, NULL, 0 }, -/* 0x87 */ { NULL, NULL, 0 }, -/* 0x88 */ { NULL, NULL, 0 }, -/* 0x89 */ { NULL, NULL, 0 }, -/* 0x8a */ { NULL, NULL, 0 }, -/* 0x8b */ { NULL, NULL, 0 }, -/* 0x8c */ { NULL, NULL, 0 }, -/* 0x8d */ { NULL, NULL, 0 }, -/* 0x8e */ { NULL, NULL, 0 }, -/* 0x8f */ { NULL, NULL, 0 }, -/* 0x90 */ { NULL, NULL, 0 }, -/* 0x91 */ { NULL, NULL, 0 }, -/* 0x92 */ { NULL, NULL, 0 }, -/* 0x93 */ { NULL, NULL, 0 }, -/* 0x94 */ { NULL, NULL, 0 }, -/* 0x95 */ { NULL, NULL, 0 }, -/* 0x96 */ { NULL, NULL, 0 }, -/* 0x97 */ { NULL, NULL, 0 }, -/* 0x98 */ { NULL, NULL, 0 }, -/* 0x99 */ { NULL, NULL, 0 }, -/* 0x9a */ { NULL, NULL, 0 }, -/* 0x9b */ { NULL, NULL, 0 }, -/* 0x9c */ { NULL, NULL, 0 }, -/* 0x9d */ { NULL, NULL, 0 }, -/* 0x9e */ { NULL, NULL, 0 }, -/* 0x9f */ { NULL, NULL, 0 }, -/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK}, -/* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC }, -/* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK }, -/* 0xa3 */ { NULL, NULL, 0 }, -/* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 }, -/* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK }, -/* 0xa6 */ { NULL, NULL, 0 }, -/* 0xa7 */ { NULL, NULL, 0 }, -/* 0xa8 */ { NULL, NULL, 0 }, -/* 0xa9 */ { NULL, NULL, 0 }, -/* 0xaa */ { NULL, NULL, 0 }, -/* 0xab */ { NULL, NULL, 0 }, -/* 0xac */ { NULL, NULL, 0 }, -/* 0xad */ { NULL, NULL, 0 }, -/* 0xae */ { NULL, NULL, 0 }, -/* 0xaf */ { NULL, NULL, 0 }, -/* 0xb0 */ { NULL, NULL, 0 }, -/* 0xb1 */ { NULL, NULL, 0 }, -/* 0xb2 */ { NULL, NULL, 0 }, -/* 0xb3 */ { NULL, NULL, 0 }, -/* 0xb4 */ { NULL, NULL, 0 }, -/* 0xb5 */ { NULL, NULL, 0 }, -/* 0xb6 */ { NULL, NULL, 0 }, -/* 0xb7 */ { NULL, NULL, 0 }, -/* 0xb8 */ { NULL, NULL, 0 }, -/* 0xb9 */ { NULL, NULL, 0 }, -/* 0xba */ { NULL, NULL, 0 }, -/* 0xbb */ { NULL, NULL, 0 }, -/* 0xbc */ { NULL, NULL, 0 }, -/* 0xbd */ { NULL, NULL, 0 }, -/* 0xbe */ { NULL, NULL, 0 }, -/* 0xbf */ { NULL, NULL, 0 }, -/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK }, -/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER}, -/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER}, -/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER}, -/* 0xc4 */ { NULL, NULL, 0 }, -/* 0xc5 */ { NULL, NULL, 0 }, -/* 0xc6 */ { NULL, NULL, 0 }, -/* 0xc7 */ { NULL, NULL, 0 }, -/* 0xc8 */ { NULL, NULL, 0 }, -/* 0xc9 */ { NULL, NULL, 0 }, -/* 0xca */ { NULL, NULL, 0 }, -/* 0xcb */ { NULL, NULL, 0 }, -/* 0xcc */ { NULL, NULL, 0 }, -/* 0xcd */ { NULL, NULL, 0 }, -/* 0xce */ { NULL, NULL, 0 }, -/* 0xcf */ { NULL, NULL, 0 }, -/* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST}, -/* 0xd1 */ { "SMBsendb",NULL,AS_GUEST}, -/* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST}, -/* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST}, -/* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST}, -/* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST}, -/* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST}, -/* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST}, -/* 0xd8 */ { NULL, NULL, 0 }, -/* 0xd9 */ { NULL, NULL, 0 }, -/* 0xda */ { NULL, NULL, 0 }, -/* 0xdb */ { NULL, NULL, 0 }, -/* 0xdc */ { NULL, NULL, 0 }, -/* 0xdd */ { NULL, NULL, 0 }, -/* 0xde */ { NULL, NULL, 0 }, -/* 0xdf */ { NULL, NULL, 0 }, -/* 0xe0 */ { NULL, NULL, 0 }, -/* 0xe1 */ { NULL, NULL, 0 }, -/* 0xe2 */ { NULL, NULL, 0 }, -/* 0xe3 */ { NULL, NULL, 0 }, -/* 0xe4 */ { NULL, NULL, 0 }, -/* 0xe5 */ { NULL, NULL, 0 }, -/* 0xe6 */ { NULL, NULL, 0 }, -/* 0xe7 */ { NULL, NULL, 0 }, -/* 0xe8 */ { NULL, NULL, 0 }, -/* 0xe9 */ { NULL, NULL, 0 }, -/* 0xea */ { NULL, NULL, 0 }, -/* 0xeb */ { NULL, NULL, 0 }, -/* 0xec */ { NULL, NULL, 0 }, -/* 0xed */ { NULL, NULL, 0 }, -/* 0xee */ { NULL, NULL, 0 }, -/* 0xef */ { NULL, NULL, 0 }, -/* 0xf0 */ { NULL, NULL, 0 }, -/* 0xf1 */ { NULL, NULL, 0 }, -/* 0xf2 */ { NULL, NULL, 0 }, -/* 0xf3 */ { NULL, NULL, 0 }, -/* 0xf4 */ { NULL, NULL, 0 }, -/* 0xf5 */ { NULL, NULL, 0 }, -/* 0xf6 */ { NULL, NULL, 0 }, -/* 0xf7 */ { NULL, NULL, 0 }, -/* 0xf8 */ { NULL, NULL, 0 }, -/* 0xf9 */ { NULL, NULL, 0 }, -/* 0xfa */ { NULL, NULL, 0 }, -/* 0xfb */ { NULL, NULL, 0 }, -/* 0xfc */ { NULL, NULL, 0 }, -/* 0xfd */ { NULL, NULL, 0 }, -/* 0xfe */ { NULL, NULL, 0 }, -/* 0xff */ { NULL, NULL, 0 } - -}; - -/******************************************************************* - Dump a packet to a file. -********************************************************************/ - -static void smb_dump(const char *name, int type, char *data, ssize_t len) -{ - int fd, i; - pstring fname; - if (DEBUGLEVEL < 50) return; - - if (len < 4) len = smb_len(data)+4; - for (i=1;i<100;i++) { - slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i, - type ? "req" : "resp"); - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644); - if (fd != -1 || errno != EEXIST) break; - } - if (fd != -1) { - 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 %lu\n", fname, (unsigned long)len)); - } -} - - -/**************************************************************************** - Do a switch on the message type, and return the response size -****************************************************************************/ - -static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize) -{ - static pid_t pid= (pid_t)-1; - int outsize = 0; - extern uint16 global_smbpid; - - type &= 0xff; - - if (pid == (pid_t)-1) - pid = sys_getpid(); - - errno = 0; - last_message = type; - - /* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */ - if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) { - DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf))); - exit_server("Non-SMB packet"); - return(-1); - } - - /* yuck! this is an interim measure before we get rid of our - current inbuf/outbuf system */ - global_smbpid = SVAL(inbuf,smb_pid); - - if (smb_messages[type].fn == NULL) { - DEBUG(0,("Unknown message type %d!\n",type)); - smb_dump("Unknown", 1, inbuf, size); - outsize = reply_unknown(inbuf,outbuf); - } else { - int flags = smb_messages[type].flags; - static uint16 last_session_tag = UID_FIELD_INVALID; - /* In share mode security we must ignore the vuid. */ - uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid); - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - - DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid)); - - smb_dump(smb_fn_name(type), 1, inbuf, size); - if(global_oplock_break) { - if(flags & QUEUE_IN_OPLOCK) { - /* - * Queue this message as we are the process of an oplock break. - */ - - DEBUG( 2, ( "switch_message: queueing message due to being in " ) ); - DEBUGADD( 2, ( "oplock break state.\n" ) ); - - push_oplock_pending_smb_message( inbuf, size ); - return -1; - } - } - - /* Ensure this value is replaced in the incoming packet. */ - SSVAL(inbuf,smb_uid,session_tag); - - /* - * Ensure the correct username is in current_user_info. - * This is a really ugly bugfix for problems with - * multiple session_setup_and_X's being done and - * allowing %U and %G substitutions to work correctly. - * There is a reason this code is done here, don't - * move it unless you know what you're doing... :-). - * JRA. - */ - - if (session_tag != last_session_tag) { - user_struct *vuser = NULL; - - last_session_tag = session_tag; - if(session_tag != UID_FIELD_INVALID) - vuser = get_valid_user_struct(session_tag); - if(vuser != NULL) - set_current_user_info(&vuser->user); - } - - /* does this protocol need to be run as root? */ - if (!(flags & AS_USER)) - change_to_root_user(); - - /* does this protocol need a valid tree connection? */ - if ((flags & AS_USER) && !conn) - return ERROR_DOS(ERRSRV, ERRinvnid); - - - /* does this protocol need to be run as the connected user? */ - if ((flags & AS_USER) && !change_to_user(conn,session_tag)) { - if (flags & AS_GUEST) - flags &= ~AS_USER; - else - return(ERROR_DOS(ERRSRV,ERRaccess)); - } - - /* this code is to work around a bug is MS client 3 without - introducing a security hole - it needs to be able to do - print queue checks as guest if it isn't logged in properly */ - if (flags & AS_USER) - flags &= ~AS_GUEST; - - /* does it need write permission? */ - if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) - return(ERROR_DOS(ERRSRV,ERRaccess)); - - /* ipc services are limited */ - if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) - return(ERROR_DOS(ERRSRV,ERRaccess)); - - /* load service specific parameters */ - 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) && (!change_to_guest() || - !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) - return(ERROR_DOS(ERRSRV,ERRaccess)); - - last_inbuf = inbuf; - - outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize); + mem_ctx = talloc_init("smbd_process_init talloc"); + if (!mem_ctx) { + DEBUG(0,("smbd_process_init: ERROR: No memory\n")); + exit(1); } + namecache_enable(); - smb_dump(smb_fn_name(type), 0, outbuf, outsize); - - return(outsize); -} - - -/**************************************************************************** - Construct a reply to the incoming packet. -****************************************************************************/ - -static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) -{ - int type = CVAL(inbuf,smb_com); - int outsize = 0; - int msg_type = CVAL(inbuf,0); - - GetTimeOfDay(&smb_last_time); - - chain_size = 0; - file_chain_reset(); - reset_chain_p(); - - if (msg_type != 0) - return(reply_special(inbuf,outbuf)); - - construct_reply_common(inbuf, outbuf); - - outsize = switch_message(type,inbuf,outbuf,size,bufsize); - - outsize += chain_size; - - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - return(outsize); -} + if (!locking_init(0)) + exit(1); -/**************************************************************************** - Keep track of the number of running smbd's. This functionality is used to - 'hard' limit Samba overhead on resource constrained systems. -****************************************************************************/ + if (!share_info_db_init()) + exit(1); -static BOOL process_count_update_successful = False; + if (!init_registry()) + exit(1); -static int32 increment_smbd_process_count(void) -{ - int32 total_smbds; + /* possibly reload the services file. */ + reload_services(NULL, True); - if (lp_max_smbd_processes()) { - total_smbds = 0; - if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1) - return 1; - process_count_update_successful = True; - return total_smbds + 1; + if(!get_global_sam_sid()) { + DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); + exit(1); } - return 1; -} - -void decrement_smbd_process_count(void) -{ - int32 total_smbds; - - if (lp_max_smbd_processes() && process_count_update_successful) { - total_smbds = 1; - tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, -1); - } -} - -static BOOL smbd_process_limit(void) -{ - int32 total_smbds; - - if (lp_max_smbd_processes()) { - - /* Always add one to the smbd process count, as exit_server() always - * subtracts one. - */ - if (!conn_tdb_ctx()) { - DEBUG(0,("smbd_process_limit: max smbd processes parameter set with status parameter not \ -set. Ignoring max smbd restriction.\n")); - return False; - } - - total_smbds = increment_smbd_process_count(); - return total_smbds > lp_max_smbd_processes(); + if (!init_account_policy()) { + DEBUG(0,("Could not open account policy tdb.\n")); + exit(1); } - else - return False; -} - -/**************************************************************************** - Process an smb from the client - split out from the smbd_process() code so - it can be used by the oplock break code. -****************************************************************************/ - -void process_smb(char *inbuf, char *outbuf) -{ - static int trans_num; - int msg_type = CVAL(inbuf,0); - int32 len = smb_len(inbuf); - int nread = len + 4; - - DO_PROFILE_INC(smb_count); - if (trans_num == 0) { - /* on the first packet, check the global hosts allow/ hosts - deny parameters before doing any parsing of the packet - passed to us by the client. This prevents attacks on our - parsing code from hosts not in the hosts allow list */ - if (smbd_process_limit() || - !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))) { - /* send a negative session response "not listening on calling name" */ - static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81}; - DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) ); - (void)send_smb(smbd_server_fd(),(char *)buf); - exit_server("connection denied"); - } + if (*lp_rootdir()) { + if (sys_chroot(lp_rootdir()) == 0) + DEBUG(2,("Changed root to %s\n", lp_rootdir())); } - DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) ); - DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) ); - - if (msg_type == 0) - show_msg(inbuf); - else if(msg_type == SMBkeepalive) - return; /* Keepalive packet. */ - - nread = construct_reply(inbuf,outbuf,nread,max_send); - - if(nread > 0) { - if (CVAL(outbuf,0) == 0) - show_msg(outbuf); + /* Setup oplocks */ + if (!init_oplocks()) + exit(1); - if (nread != smb_len(outbuf) + 4) { - DEBUG(0,("ERROR: Invalid message response size! %d %d\n", - nread, smb_len(outbuf))); - } else if (!send_smb(smbd_server_fd(),outbuf)) { - exit_server("process_smb: send_smb failed."); - } - } - trans_num++; -} - -/**************************************************************************** - Return a string containing the function name of a SMB command. -****************************************************************************/ - -const char *smb_fn_name(int type) -{ - const char *unknown_name = "SMBunknown"; - - if (smb_messages[type].name == NULL) - return(unknown_name); - - return(smb_messages[type].name); -} - -/**************************************************************************** - Helper functions for contruct_reply. -****************************************************************************/ - -static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_EXTENDED_SECURITY|FLAGS2_32_BIT_ERROR_CODES; - -void remove_from_common_flags2(uint32 v) -{ - common_flags2 &= ~v; -} - -void construct_reply_common(char *inbuf,char *outbuf) -{ - memset(outbuf,'\0',smb_size); - - set_message(outbuf,0,0,True); - SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); + /* Setup change notify */ + if (!init_change_notify()) + exit(1); + + /* Setup the AUTH subsystem */ + if (!auth_init()) + exit(1); + + /* Setup the PASSDB subsystem */ + if (!passdb_init()) + exit(1); + if(!initialize_password_db(False)) + exit(1); + + /* Setup the NTVFS subsystem */ + if (!ntvfs_init()) + exit(1); + + /* Setup the DCERPC subsystem */ + if (!dcesrv_init()) + exit(1); + + /* re-initialise the timezone */ + TimeInit(); - memcpy(outbuf+4,inbuf+4,4); - SCVAL(outbuf,smb_rcls,SMB_SUCCESS); - SCVAL(outbuf,smb_reh,0); - SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); - SSVAL(outbuf,smb_flg2, - (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) | - common_flags2); - - SSVAL(outbuf,smb_err,SMB_SUCCESS); - SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); - SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); - SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid)); - SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid)); -} - -/**************************************************************************** - Construct a chained reply and add it to the already made reply -****************************************************************************/ - -int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) -{ - static char *orig_inbuf; - static char *orig_outbuf; - int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0); - unsigned smb_off2 = SVAL(inbuf,smb_vwv1); - char *inbuf2, *outbuf2; - int outsize2; - char inbuf_saved[smb_wct]; - char outbuf_saved[smb_wct]; - int wct = CVAL(outbuf,smb_wct); - int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct); - - /* maybe its not chained */ - if (smb_com2 == 0xFF) { - SCVAL(outbuf,smb_vwv0,0xFF); - return outsize; - } - - if (chain_size == 0) { - /* this is the first part of the chain */ - orig_inbuf = inbuf; - orig_outbuf = outbuf; - } - - /* - * The original Win95 redirector dies on a reply to - * a lockingX and read chain unless the chain reply is - * 4 byte aligned. JRA. - */ - - outsize = (outsize + 3) & ~3; - - /* we need to tell the client where the next part of the reply will be */ - SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf)); - SCVAL(outbuf,smb_vwv0,smb_com2); - - /* remember how much the caller added to the chain, only counting stuff - after the parameter words */ - chain_size += outsize - smb_wct; - - /* work out pointers into the original packets. The - headers on these need to be filled in */ - inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct; - outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct; - - /* remember the original command type */ - smb_com1 = CVAL(orig_inbuf,smb_com); - - /* save the data which will be overwritten by the new headers */ - memcpy(inbuf_saved,inbuf2,smb_wct); - memcpy(outbuf_saved,outbuf2,smb_wct); - - /* give the new packet the same header as the last part of the SMB */ - memmove(inbuf2,inbuf,smb_wct); - - /* create the in buffer */ - SCVAL(inbuf2,smb_com,smb_com2); - - /* create the out buffer */ - construct_reply_common(inbuf2, outbuf2); - - DEBUG(3,("Chained message\n")); - show_msg(inbuf2); - - /* process the request */ - outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size, - bufsize-chain_size); - - /* copy the new reply and request headers over the old ones, but - preserve the smb_com field */ - memmove(orig_outbuf,outbuf2,smb_wct); - SCVAL(orig_outbuf,smb_com,smb_com1); - - /* restore the saved data, being careful not to overwrite any - data from the reply header */ - memcpy(inbuf2,inbuf_saved,smb_wct); - - { - int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf); - if (ofs < 0) ofs = 0; - memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs); - } - - return outsize2; -} - -/**************************************************************************** - Setup the needed select timeout. -****************************************************************************/ - -static int setup_select_timeout(void) -{ - int select_timeout; - int t; - - select_timeout = blocking_locks_timeout(SMBD_SELECT_TIMEOUT); - select_timeout *= 1000; - - t = change_notify_timeout(); - if (t != -1) - select_timeout = MIN(select_timeout, t*1000); - - if (print_notify_messages_pending()) - select_timeout = MIN(select_timeout, 1000); - - return select_timeout; -} - -/**************************************************************************** - Check if services need reloading. -****************************************************************************/ - -void check_reload(int t) -{ - static time_t last_smb_conf_reload_time = 0; - - if(last_smb_conf_reload_time == 0) - last_smb_conf_reload_time = t; - - if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) { - reload_services(True); - reload_after_sighup = False; - last_smb_conf_reload_time = t; - } -} - -/**************************************************************************** - Process any timeout housekeeping. Return False if the caller should exit. -****************************************************************************/ - -static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time) -{ - static time_t last_keepalive_sent_time = 0; - static time_t last_idle_closed_check = 0; - time_t t; - BOOL allidle = True; - extern int keepalive; - - if (smb_read_error == READ_EOF) { - DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n")); - return False; - } - - if (smb_read_error == READ_ERROR) { - DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n", - strerror(errno))); - return False; - } - - if (smb_read_error == READ_BAD_SIG) { - DEBUG(3,("timeout_processing: receive_smb error bad smb signature. Exiting\n")); - return False; - } - - *last_timeout_processing_time = t = time(NULL); - - if(last_keepalive_sent_time == 0) - last_keepalive_sent_time = t; - - if(last_idle_closed_check == 0) - last_idle_closed_check = t; - - /* become root again if waiting */ - change_to_root_user(); - - /* run all registered idle events */ - smb_run_idle_events(t); - - /* check if we need to reload services */ - check_reload(t); - - /* automatic timeout if all connections are closed */ - if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT) { - DEBUG( 2, ( "Closing idle connection\n" ) ); - return False; - } else { - last_idle_closed_check = t; - } - - if (keepalive && (t - last_keepalive_sent_time)>keepalive) { - extern struct auth_context *negprot_global_auth_context; - if (!send_keepalive(smbd_server_fd())) { - DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); - return False; - } - - /* send a keepalive for a password server or the like. - This is attached to the auth_info created in the - negprot */ - if (negprot_global_auth_context && negprot_global_auth_context->challenge_set_method - && negprot_global_auth_context->challenge_set_method->send_keepalive) { - - negprot_global_auth_context->challenge_set_method->send_keepalive - (&negprot_global_auth_context->challenge_set_method->private_data); - } - - last_keepalive_sent_time = t; - } - - /* check for connection timeouts */ - allidle = conn_idle_all(t, deadtime); - - if (allidle && conn_num_open()>0) { - DEBUG(2,("Closing idle connection 2.\n")); - return False; - } - - if(global_machine_password_needs_changing && - /* for ADS we need to do a regular ADS password change, not a domain - password change */ - lp_security() == SEC_DOMAIN) { - - unsigned char trust_passwd_hash[16]; - time_t lct; - - /* - * We're in domain level security, and the code that - * read the machine password flagged that the machine - * password needs changing. - */ - - /* - * First, open the machine password file with an exclusive lock. - */ - - if (secrets_lock_trust_account_password(lp_workgroup(), True) == False) { - DEBUG(0,("process: unable to lock the machine account password for \ -machine %s in domain %s.\n", global_myname(), lp_workgroup() )); - return True; - } - - if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) { - DEBUG(0,("process: unable to read the machine account password for \ -machine %s in domain %s.\n", global_myname(), lp_workgroup())); - secrets_lock_trust_account_password(lp_workgroup(), False); - return True; - } - - /* - * Make sure someone else hasn't already done this. - */ - - if(t < lct + lp_machine_password_timeout()) { - global_machine_password_needs_changing = False; - secrets_lock_trust_account_password(lp_workgroup(), False); - return True; - } - - /* always just contact the PDC here */ - - change_trust_account_password( lp_workgroup(), NULL); - global_machine_password_needs_changing = False; - secrets_lock_trust_account_password(lp_workgroup(), False); - } - - /* - * Check to see if we have any blocking locks - * outstanding on the queue. - */ - process_blocking_lock_queue(t); - - /* update printer queue caches if necessary */ - - update_monitored_printq_cache(); - - /* - * Check to see if we have any change notifies - * outstanding on the queue. - */ - process_pending_change_notify_queue(t); - - /* - * Now we are root, check if the log files need pruning. - * Force a log file check. - */ - force_check_log_size(); - check_log_size(); - - /* Send any queued printer notify message to interested smbd's. */ - - print_notify_send_messages(0); - - /* - * Modify the select timeout depending upon - * what we have remaining in our queues. - */ - - *select_timeout = setup_select_timeout(); - - return True; + talloc_destroy(mem_ctx); } -/**************************************************************************** - process commands from the client -****************************************************************************/ - -void smbd_process(void) -{ - extern int smb_echo_count; - time_t last_timeout_processing_time = time(NULL); - unsigned int num_smbs = 0; - const size_t total_buffer_size = BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN; - - InBuffer = (char *)malloc(total_buffer_size); - OutBuffer = (char *)malloc(total_buffer_size); - if ((InBuffer == NULL) || (OutBuffer == NULL)) - return; - -#if defined(DEVELOPER) - clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size); - clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size); -#endif - - max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); - - while (True) { - int deadtime = lp_deadtime()*60; - int select_timeout = setup_select_timeout(); - int num_echos; - - if (deadtime <= 0) - deadtime = DEFAULT_SMBD_TIMEOUT; - - errno = 0; - - /* free up temporary memory */ - lp_talloc_free(); - main_loop_talloc_free(); - - /* run all registered idle events */ - smb_run_idle_events(time(NULL)); - - - /* Did someone ask for immediate checks on things like blocking locks ? */ - if (select_timeout == 0) { - if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time)) - return; - num_smbs = 0; /* Reset smb counter. */ - } - -#if defined(DEVELOPER) - clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size); -#endif - - while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) { - if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time)) - return; - num_smbs = 0; /* Reset smb counter. */ - } - - /* - * Ensure we do timeout processing if the SMB we just got was - * only an echo request. This allows us to set the select - * timeout in 'receive_message_or_smb()' to any value we like - * without worrying that the client will send echo requests - * faster than the select timeout, thus starving out the - * essential processing (change notify, blocking locks) that - * the timeout code does. JRA. - */ - num_echos = smb_echo_count; - - clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size); - - process_smb(InBuffer, OutBuffer); - - if (smb_echo_count != num_echos) { - if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time)) - return; - num_smbs = 0; /* Reset smb counter. */ - } - - num_smbs++; - - /* - * If we are getting smb requests in a constant stream - * with no echos, make sure we attempt timeout processing - * every select_timeout milliseconds - but only check for this - * every 200 smb requests. - */ - - if ((num_smbs % 200) == 0) { - time_t new_check_time = time(NULL); - if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) { - if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time)) - return; - num_smbs = 0; /* Reset smb counter. */ - last_timeout_processing_time = new_check_time; /* Reset time. */ - } - } - - /* The timeout_processing function isn't run nearly - often enough to implement 'max log size' without - overrunning the size of the file by many megabytes. - This is especially true if we are running at debug - level 10. Checking every 50 SMBs is a nice - tradeoff of performance vs log file size overrun. */ - - if ((num_smbs % 50) == 0 && need_to_check_log_size()) { - change_to_root_user(); - check_log_size(); - } - } -} diff --git a/source/smbd/process_model.c b/source/smbd/process_model.c new file mode 100644 index 00000000000..121b35aba44 --- /dev/null +++ b/source/smbd/process_model.c @@ -0,0 +1,115 @@ +/* + Unix SMB/CIFS implementation. + process model manager - main loop + Copyright (C) Andrew Tridgell 1992-2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +/* the list of currently registered process models */ +static struct { + struct model_ops *ops; +} *models = NULL; +static int num_models; + +/* + register a process model. + + The 'name' can be later used by other backends to find the operations + structure for this backend. +*/ +static NTSTATUS register_process_model(void *_ops) +{ + const struct model_ops *ops = _ops; + + if (process_model_byname(ops->name) != NULL) { + /* its already registered! */ + DEBUG(0,("PROCESS_MODEL '%s' already registered\n", + ops->name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + models = Realloc(models, sizeof(models[0]) * (num_models+1)); + if (!models) { + smb_panic("out of memory in register_process_model"); + } + + models[num_models].ops = smb_xmemdup(ops, sizeof(*ops)); + models[num_models].ops->name = smb_xstrdup(ops->name); + + num_models++; + + DEBUG(3,("PROCESS_MODEL '%s' registered\n", + ops->name)); + + return NT_STATUS_OK; +} + +/* + return the operations structure for a named backend of the specified type +*/ +const struct model_ops *process_model_byname(const char *name) +{ + int i; + + for (i=0;i<num_models;i++) { + if (strcmp(models[i].ops->name, name) == 0) { + return models[i].ops; + } + } + + return NULL; +} + +/* + return the PROCESS_MODEL module version, and the size of some critical types + This can be used by process model modules to either detect compilation errors, or provide + multiple implementations for different smbd compilation options in one module +*/ +const struct process_model_critical_sizes *process_model_version(void) +{ + static const struct process_model_critical_sizes critical_sizes = { + PROCESS_MODEL_VERSION, + sizeof(struct model_ops), + sizeof(struct server_context), + sizeof(struct event_context), + sizeof(struct fd_event) + }; + + return &critical_sizes; +} + +/* + initialise the PROCESS_MODEL subsystem +*/ +BOOL process_model_init(void) +{ + NTSTATUS status; + + status = register_subsystem("process_model", register_process_model); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + /* FIXME: Perhaps panic if a basic process model, such as simple, fails to initialise? */ + static_init_process_model; + + DEBUG(3,("PROCESS subsystem version %d initialised\n", PROCESS_MODEL_VERSION)); + return True; +} diff --git a/source/smbd/process_model.h b/source/smbd/process_model.h new file mode 100644 index 00000000000..688ae652262 --- /dev/null +++ b/source/smbd/process_model.h @@ -0,0 +1,69 @@ +/* + Unix SMB/CIFS implementation. + process model manager - main loop + Copyright (C) Andrew Tridgell 1992-2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef SAMBA_PROCESS_MODEL_H +#define SAMBA_PROCESS_MODEL_H + +/* modules can use the following to determine if the interface has changed + * please increment the version number after each interface change + * with a comment and maybe update struct process_model_critical_sizes. + */ +/* version 1 - initial version - metze */ +#define PROCESS_MODEL_VERSION 1 + +/* the process model operations structure - contains function pointers to + the model-specific implementations of each operation */ +struct model_ops { + /* the name of the process_model */ + const char *name; + + /* called at startup when the model is selected */ + void (*model_startup)(void); + + /* function to accept new connection */ + void (*accept_connection)(struct event_context *, struct fd_event *, time_t, uint16); + + /* function to accept new rpc over tcp connection */ + void (*accept_rpc_connection)(struct event_context *, struct fd_event *, time_t, uint16); + + /* function to terminate a connection */ + void (*terminate_connection)(struct server_context *smb, const char *reason); + + /* function to terminate a connection */ + void (*terminate_rpc_connection)(void *r, const char *reason); + + /* function to exit server */ + void (*exit_server)(struct server_context *smb, const char *reason); + + /* returns process or thread id */ + int (*get_id)(struct request_context *req); +}; + +/* this structure is used by modules to determine the size of some critical types */ +struct process_model_critical_sizes { + int interface_version; + int sizeof_model_ops; + int sizeof_server_context; + int sizeof_event_context; + int sizeof_fd_event; +}; + +#endif /* SAMBA_PROCESS_MODEL_H */ diff --git a/source/smbd/process_model.m4 b/source/smbd/process_model.m4 new file mode 100644 index 00000000000..a7f6fb07931 --- /dev/null +++ b/source/smbd/process_model.m4 @@ -0,0 +1,27 @@ +dnl # Server process model subsystem + +SMB_MODULE(process_model_single,PROCESS_MODEL,STATIC,[smbd/process_single.o]) +SMB_MODULE(process_model_standard,PROCESS_MODEL,STATIC,[smbd/process_standard.o]) + +################################################# +# check for pthread support +AC_MSG_CHECKING(whether to use pthreads) +AC_ARG_WITH(pthreads, +[ --with-pthreads Include pthreads (default=no) ], +[ case "$withval" in + yes) + AC_MSG_RESULT(yes) + SMB_MODULE_DEFAULT(process_model_thread,STATIC) + ;; + *) + AC_MSG_RESULT(no) + ;; + esac ], +AC_MSG_RESULT(no) +) + +SMB_MODULE(process_model_thread,PROCESS_MODEL,NOT, + [smbd/process_thread.o],[],[-lpthread]) + +SMB_SUBSYSTEM(PROCESS_MODEL,smbd/process_model.o, + [],smbd/process_model_public_proto.h) diff --git a/source/smbd/process_single.c b/source/smbd/process_single.c new file mode 100644 index 00000000000..0c626e45c63 --- /dev/null +++ b/source/smbd/process_single.c @@ -0,0 +1,130 @@ +/* + Unix SMB/CIFS implementation. + process model: process (1 process handles all client connections) + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* + called when the process model is selected +*/ +static void model_startup(void) +{ + smbd_process_init(); +} + +/* + called when a listening socket becomes readable +*/ +static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags) +{ + int accepted_fd; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + struct model_ops *model_ops = fde->private; + + /* accept an incoming connection. */ + accepted_fd = accept(fde->fd,&addr,&in_addrlen); + if (accepted_fd == -1) { + DEBUG(0,("accept_connection_single: accept: %s\n", + strerror(errno))); + return; + } + + /* create a smb server context and add it to out event + handling */ + init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); + + /* return to event handling */ +} + + +/* + called when a rpc listening socket becomes readable +*/ +static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags) +{ + int accepted_fd; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + + /* accept an incoming connection. */ + accepted_fd = accept(fde->fd,&addr,&in_addrlen); + if (accepted_fd == -1) { + DEBUG(0,("accept_connection_single: accept: %s\n", + strerror(errno))); + return; + } + + init_rpc_session(ev, fde->private, accepted_fd); +} + +/* called when a SMB connection goes down */ +static void terminate_connection(struct server_context *server, const char *reason) +{ + server_terminate(server); +} + +/* called when a rpc connection goes down */ +static void terminate_rpc_connection(void *r, const char *reason) +{ + rpc_server_terminate(r); +} + +static int get_id(struct request_context *req) +{ + return (int)req->smb->pid; +} + +static void single_exit_server(struct server_context *smb, const char *reason) +{ + DEBUG(1,("single_exit_server: reason[%s]\n",reason)); +} + +/* + initialise the single process model, registering ourselves with the process model subsystem + */ +NTSTATUS process_model_single_init(void) +{ + NTSTATUS ret; + struct model_ops ops; + + ZERO_STRUCT(ops); + + /* fill in our name */ + ops.name = "single"; + + /* fill in all the operations */ + ops.model_startup = model_startup; + ops.accept_connection = accept_connection; + ops.accept_rpc_connection = accept_rpc_connection; + ops.terminate_connection = terminate_connection; + ops.terminate_rpc_connection = terminate_rpc_connection; + ops.exit_server = single_exit_server; + ops.get_id = get_id; + + /* register ourselves with the PROCESS_MODEL subsystem. */ + ret = register_backend("process_model", &ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register process_model 'single'!\n")); + return ret; + } + + return ret; +} diff --git a/source/smbd/process_standard.c b/source/smbd/process_standard.c new file mode 100644 index 00000000000..8a71739d2a5 --- /dev/null +++ b/source/smbd/process_standard.c @@ -0,0 +1,172 @@ +/* + Unix SMB/CIFS implementation. + process model: standard (1 process per client connection) + Copyright (C) Andrew Tridgell 1992-2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* + called when the process model is selected +*/ +static void model_startup(void) +{ +} + +/* + called when a listening socket becomes readable +*/ +static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags) +{ + int accepted_fd; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + pid_t pid; + struct model_ops *model_ops = fde->private; + + accepted_fd = accept(fde->fd,&addr,&in_addrlen); + if (accepted_fd == -1) { + DEBUG(0,("accept_connection_standard: accept: %s\n", + strerror(errno))); + return; + } + + pid = fork(); + + if (pid != 0) { + /* parent or error code ... */ + + close(accepted_fd); + /* go back to the event loop */ + return; + } + + /* Child code ... */ + + /* close all the listening sockets */ + event_remove_fd_all_handler(ev, model_ops->accept_connection); + event_remove_fd_all_handler(ev, model_ops->accept_rpc_connection); + + /* tdb needs special fork handling */ + if (tdb_reopen_all() == -1) { + DEBUG(0,("accept_connection_standard: tdb_reopen_all failed.\n")); + } + + /* Load DSO's */ + init_modules(); + + /* initialize new process */ + smbd_process_init(); + + init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); + + /* return to the event loop */ +} + +/* + called when a rpc listening socket becomes readable +*/ +static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags) +{ + int accepted_fd; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + pid_t pid; + + accepted_fd = accept(fde->fd,&addr,&in_addrlen); + if (accepted_fd == -1) { + DEBUG(0,("accept_connection_standard: accept: %s\n", + strerror(errno))); + return; + } + + pid = fork(); + + if (pid != 0) { + /* parent or error code ... */ + close(accepted_fd); + /* go back to the event loop */ + return; + } + + /* Child code ... */ + + /* close all the listening sockets */ + event_remove_fd_all_handler(ev, accept_connection); + event_remove_fd_all_handler(ev, accept_rpc_connection); + + init_rpc_session(ev, fde->private, accepted_fd); +} + +/* called when a SMB connection goes down */ +static void terminate_connection(struct server_context *server, const char *reason) +{ + server_terminate(server); + /* terminate this process */ + exit(0); +} + +/* called when a rpc connection goes down */ +static void terminate_rpc_connection(void *r, const char *reason) +{ + rpc_server_terminate(r); + /* terminate this process */ + exit(0); +} + +static int get_id(struct request_context *req) +{ + return (int)req->smb->pid; +} + +static void standard_exit_server(struct server_context *smb, const char *reason) +{ + DEBUG(1,("standard_exit_server: reason[%s]\n",reason)); +} + +/* + initialise the standard process model, registering ourselves with the process model subsystem + */ +NTSTATUS process_model_standard_init(void) +{ + NTSTATUS ret; + struct model_ops ops; + + ZERO_STRUCT(ops); + + /* fill in our name */ + ops.name = "standard"; + + /* fill in all the operations */ + ops.model_startup = model_startup; + ops.accept_connection = accept_connection; + ops.accept_rpc_connection = accept_rpc_connection; + ops.terminate_connection = terminate_connection; + ops.terminate_rpc_connection = terminate_rpc_connection; + ops.exit_server = standard_exit_server; + ops.get_id = get_id; + + /* register ourselves with the PROCESS_MODEL subsystem. */ + ret = register_backend("process_model", &ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register process_model 'standard'!\n")); + return ret; + } + + return ret; +} diff --git a/source/smbd/process_thread.c b/source/smbd/process_thread.c new file mode 100644 index 00000000000..dcd2f456af5 --- /dev/null +++ b/source/smbd/process_thread.c @@ -0,0 +1,503 @@ +/* + Unix SMB/CIFS implementation. + thread model: standard (1 thread per client connection) + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "pthread.h" +#ifdef HAVE_BACKTRACE +#include "execinfo.h" +#endif + +static void *connection_thread(void *thread_parm) +{ + struct event_context *ev = thread_parm; + /* wait for action */ + event_loop_wait(ev); + +#if 0 + pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */ +#endif + return NULL; +} + +static int get_id(struct request_context *req) +{ + return (int)pthread_self(); +} + +/* + called when a listening socket becomes readable +*/ +static void accept_connection(struct event_context *ev, struct fd_event *fde, + time_t t, uint16 flags) +{ + int accepted_fd, rc; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + pthread_t thread_id; + pthread_attr_t thread_attr; + struct model_ops *model_ops = fde->private; + + /* accept an incoming connection */ + accepted_fd = accept(fde->fd,&addr,&in_addrlen); + + if (accepted_fd == -1) { + DEBUG(0,("accept_connection_thread: accept: %s\n", + strerror(errno))); + return; + } + + /* create new detached thread for this connection. The new + thread gets a new event_context with a single fd_event for + receiving from the new socket. We set that thread running + with the main event loop, then return. When we return the + main event_context is continued. + */ + ev = event_context_init(); + MUTEX_LOCK_BY_ID(MUTEX_SMBD); + init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); + MUTEX_UNLOCK_BY_ID(MUTEX_SMBD); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev); + pthread_attr_destroy(&thread_attr); + if (rc == 0) { + DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", + (unsigned long int)thread_id, accepted_fd)); + } else { + DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc)); + } +} + + +/* + called when a rpc listening socket becomes readable +*/ +static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags) +{ + int accepted_fd, rc; + struct sockaddr addr; + socklen_t in_addrlen = sizeof(addr); + pthread_t thread_id; + pthread_attr_t thread_attr; + + /* accept an incoming connection */ + accepted_fd = accept(fde->fd,&addr,&in_addrlen); + + if (accepted_fd == -1) { + DEBUG(0,("accept_connection_thread: accept: %s\n", + strerror(errno))); + return; + } + + ev = event_context_init(); + MUTEX_LOCK_BY_ID(MUTEX_SMBD); + init_rpc_session(ev, fde->private, accepted_fd); + MUTEX_UNLOCK_BY_ID(MUTEX_SMBD); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev); + pthread_attr_destroy(&thread_attr); + if (rc == 0) { + DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", + (unsigned long int)thread_id, accepted_fd)); + } else { + DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc)); + } +} + +/* called when a SMB connection goes down */ +static void terminate_connection(struct server_context *server, const char *reason) +{ + server_terminate(server); + + /* terminate this thread */ + pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ +} + +/* called when a rpc connection goes down */ +static void terminate_rpc_connection(void *r, const char *reason) +{ + rpc_server_terminate(r); + + /* terminate this thread */ + pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ +} + +/* + mutex init function for thread model +*/ +static int thread_mutex_init(smb_mutex_t *mutex, const char *name) +{ + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + mutex->mutex = memdup(&m, sizeof(m)); + if (! mutex->mutex) { + errno = ENOMEM; + return -1; + } + return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL); +} + +/* + mutex destroy function for thread model +*/ +static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name) +{ + return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex); +} + +static void mutex_start_timer(struct timeval *tp1) +{ + gettimeofday(tp1,NULL); +} + +static double mutex_end_timer(struct timeval tp1) +{ + struct timeval tp2; + gettimeofday(&tp2,NULL); + return((tp2.tv_sec - tp1.tv_sec) + + (tp2.tv_usec - tp1.tv_usec)*1.0e-6); +} + +/* + mutex lock function for thread model +*/ +static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name) +{ + pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex; + int rc; + double t; + struct timeval tp1; + /* Test below is ONLY for debugging */ + if ((rc = pthread_mutex_trylock(mutex))) { + if (rc == EBUSY) { + mutex_start_timer(&tp1); + printf("mutex lock: thread %d, lock %s not available\n", + (uint32)pthread_self(), name); + print_suspicious_usage("mutex_lock", name); + pthread_mutex_lock(mutex); + t = mutex_end_timer(tp1); + printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n", + (uint32)pthread_self(), name, t); + return 0; + } + printf("mutex lock: thread %d, lock %s failed rc=%d\n", + (uint32)pthread_self(), name, rc); + SMB_ASSERT(errno == 0); /* force error */ + } + return 0; +} + +/* + mutex unlock for thread model +*/ +static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name) +{ + return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex); +} + +/***************************************************************** + Read/write lock routines. +*****************************************************************/ +/* + rwlock init function for thread model +*/ +static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name) +{ + pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER; + rwlock->rwlock = memdup(&m, sizeof(m)); + if (! rwlock->rwlock) { + errno = ENOMEM; + return -1; + } + return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL); +} + +/* + rwlock destroy function for thread model +*/ +static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name) +{ + return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock); +} + +/* + rwlock lock for read function for thread model +*/ +static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name) +{ + pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock; + int rc; + double t; + struct timeval tp1; + /* Test below is ONLY for debugging */ + if ((rc = pthread_rwlock_tryrdlock(rwlock))) { + if (rc == EBUSY) { + mutex_start_timer(&tp1); + printf("rwlock lock_read: thread %d, lock %s not available\n", + (uint32)pthread_self(), name); + print_suspicious_usage("rwlock_lock_read", name); + pthread_rwlock_rdlock(rwlock); + t = mutex_end_timer(tp1); + printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n", + (uint32)pthread_self(), name, t); + return 0; + } + printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n", + (uint32)pthread_self(), name, rc); + SMB_ASSERT(errno == 0); /* force error */ + } + return 0; +} + +/* + rwlock lock for write function for thread model +*/ +static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name) +{ + pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock; + int rc; + double t; + struct timeval tp1; + /* Test below is ONLY for debugging */ + if ((rc = pthread_rwlock_trywrlock(rwlock))) { + if (rc == EBUSY) { + mutex_start_timer(&tp1); + printf("rwlock lock_write: thread %d, lock %s not available\n", + (uint32)pthread_self(), name); + print_suspicious_usage("rwlock_lock_write", name); + pthread_rwlock_wrlock(rwlock); + t = mutex_end_timer(tp1); + printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n", + (uint32)pthread_self(), name, t); + return 0; + } + printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n", + (uint32)pthread_self(), name, rc); + SMB_ASSERT(errno == 0); /* force error */ + } + return 0; +} + + +/* + rwlock unlock for thread model +*/ +static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name) +{ + return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock); +} + +/***************************************************************** + Log suspicious usage (primarily for possible thread-unsafe behavior. +*****************************************************************/ +static void thread_log_suspicious_usage(const char* from, const char* info) +{ + DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info)); +#ifdef HAVE_BACKTRACE + { + void *addresses[10]; + int num_addresses = backtrace(addresses, 8); + char **bt_symbols = backtrace_symbols(addresses, num_addresses); + int i; + + if (bt_symbols) { + for (i=0; i<num_addresses; i++) { + DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i])); + } + free(bt_symbols); + } + } +#endif +} + +/***************************************************************** + Log suspicious usage to stdout (primarily for possible thread-unsafe behavior. + Used in mutex code where DEBUG calls would cause recursion. +*****************************************************************/ +static void thread_print_suspicious_usage(const char* from, const char* info) +{ + printf("log_suspicious_usage: from %s info='%s'\n", from, info); +#ifdef HAVE_BACKTRACE + { + void *addresses[10]; + int num_addresses = backtrace(addresses, 8); + char **bt_symbols = backtrace_symbols(addresses, num_addresses); + int i; + + if (bt_symbols) { + for (i=0; i<num_addresses; i++) { + printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]); + } + free(bt_symbols); + } + } +#endif +} + +static uint32 thread_get_task_id(void) +{ + return (uint32)pthread_self(); +} + +static void thread_log_task_id(int fd) +{ + char *s; + + asprintf(&s, "thread %u: ", (uint32)pthread_self()); + write(fd, s, strlen(s)); + free(s); +} +/**************************************************************************** +catch serious errors +****************************************************************************/ +static void thread_sig_fault(int sig) +{ + DEBUG(0,("===============================================================\n")); + DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION_STRING)); + DEBUG(0,("===============================================================\n")); + exit(1); /* kill the whole server for now */ +} + +/******************************************************************* +setup our recursive fault handlers +********************************************************************/ +static void thread_fault_setup(void) +{ +#ifdef SIGSEGV + CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault); +#endif +#ifdef SIGBUS + CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault); +#endif +#ifdef SIGABRT + CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault); +#endif +} + +/******************************************************************* +report a fault in a thread +********************************************************************/ +static void thread_fault_handler(int sig) +{ + static int counter; + + /* try to catch recursive faults */ + thread_fault_setup(); + + counter++; /* count number of faults that have occurred */ + + DEBUG(0,("===============================================================\n")); + DEBUG(0,("INTERNAL ERROR: Signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION_STRING)); + DEBUG(0,("Please read the file BUGS.txt in the distribution\n")); + DEBUG(0,("===============================================================\n")); +#ifdef HAVE_BACKTRACE + { + void *addresses[10]; + int num_addresses = backtrace(addresses, 8); + char **bt_symbols = backtrace_symbols(addresses, num_addresses); + int i; + + if (bt_symbols) { + for (i=0; i<num_addresses; i++) { + DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i])); + } + free(bt_symbols); + } + } +#endif + pthread_exit(NULL); /* terminate failing thread only */ +} + +/* + called when the process model is selected +*/ +static void model_startup(void) +{ + struct mutex_ops m_ops; + struct debug_ops d_ops; + + ZERO_STRUCT(m_ops); + ZERO_STRUCT(d_ops); + + smbd_process_init(); + + /* register mutex/rwlock handlers */ + m_ops.mutex_init = thread_mutex_init; + m_ops.mutex_lock = thread_mutex_lock; + m_ops.mutex_unlock = thread_mutex_unlock; + m_ops.mutex_destroy = thread_mutex_destroy; + + m_ops.rwlock_init = thread_rwlock_init; + m_ops.rwlock_lock_write = thread_rwlock_lock_write; + m_ops.rwlock_lock_read = thread_rwlock_lock_read; + m_ops.rwlock_unlock = thread_rwlock_unlock; + m_ops.rwlock_destroy = thread_rwlock_destroy; + + register_mutex_handlers("thread", &m_ops); + + register_fault_handler("thread", thread_fault_handler); + + d_ops.log_suspicious_usage = thread_log_suspicious_usage; + d_ops.print_suspicious_usage = thread_print_suspicious_usage; + d_ops.get_task_id = thread_get_task_id; + d_ops.log_task_id = thread_log_task_id; + + register_debug_handlers("thread", &d_ops); +} + +static void thread_exit_server(struct server_context *smb, const char *reason) +{ + DEBUG(1,("thread_exit_server: reason[%s]\n",reason)); +} + +/* + initialise the thread process model, registering ourselves with the model subsystem + */ +NTSTATUS process_model_thread_init(void) +{ + NTSTATUS ret; + struct model_ops ops; + + ZERO_STRUCT(ops); + + /* fill in our name */ + ops.name = "thread"; + + /* fill in all the operations */ + ops.model_startup = model_startup; + ops.accept_connection = accept_connection; + ops.accept_rpc_connection = accept_rpc_connection; + ops.terminate_connection = terminate_connection; + ops.terminate_rpc_connection = terminate_rpc_connection; + ops.exit_server = thread_exit_server; + ops.get_id = get_id; + + /* register ourselves with the PROCESS_MODEL subsystem. */ + ret = register_backend("process_model", &ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register process_model 'thread'!\n")); + return ret; + } + + return ret; +} diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c deleted file mode 100644 index e439c1e571a..00000000000 --- a/source/smbd/quotas.c +++ /dev/null @@ -1,1279 +0,0 @@ -/* - Unix SMB/CIFS implementation. - support for quotas - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -/* - * This is one of the most system dependent parts of Samba, and its - * done a litle differently. Each system has its own way of doing - * things :-( - */ - -#include "includes.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_QUOTA - -#ifndef HAVE_SYS_QUOTAS - -/* just a quick hack because sysquotas.h is included before linux/quota.h */ -#ifdef QUOTABLOCK_SIZE -#undef QUOTABLOCK_SIZE -#endif - -#ifdef WITH_QUOTAS - -#if defined(VXFS_QUOTA) - -/* - * In addition to their native filesystems, some systems have Veritas VxFS. - * Declare here, define at end: reduces likely "include" interaction problems. - * David Lee <T.D.Lee@durham.ac.uk> - */ -BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); - -#endif /* VXFS_QUOTA */ - -#ifdef LINUX - -#include <sys/types.h> -#include <mntent.h> - -/* - * This shouldn't be neccessary - it should be /usr/include/sys/quota.h - * So we include all the files has *should* be in the system into a large, - * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA. - */ - -#include "samba_linux_quota.h" -#include "samba_xfs_quota.h" - -typedef struct _LINUX_SMB_DISK_QUOTA { - SMB_BIG_UINT bsize; - SMB_BIG_UINT hardlimit; /* In bsize units. */ - SMB_BIG_UINT softlimit; /* In bsize units. */ - SMB_BIG_UINT curblocks; /* In bsize units. */ - SMB_BIG_UINT ihardlimit; /* inode hard limit. */ - SMB_BIG_UINT isoftlimit; /* inode soft limit. */ - SMB_BIG_UINT curinodes; /* Current used inodes. */ -} 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, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct fs_disk_quota D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret) - ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret) - 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; - - return ret; -} - -/**************************************************************************** - Abstract out the old and new Linux quota get calls. -****************************************************************************/ - -static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct v1_kern_dqblk D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - return ret; - - dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; - dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; - dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; - dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; - dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; - dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; - dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks; - - return ret; -} - -static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct v2_kern_dqblk D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - return ret; - - dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; - dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; - dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; - dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; - dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; - dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; - dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize; - - return ret; -} - -/**************************************************************************** - Brand-new generic quota interface. -****************************************************************************/ - -static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct if_dqblk D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - return ret; - - dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE; - dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit; - dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit; - dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit; - dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit; - dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes; - dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize; - - return ret; -} - -/**************************************************************************** - Try to get the disk space from disk quotas (LINUX version). -****************************************************************************/ - -BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - int r; - SMB_STRUCT_STAT S; - FILE *fp; - LINUX_SMB_DISK_QUOTA D; - struct mntent *mnt; - SMB_DEV_T devno; - int found; - uid_t euser_id; - gid_t egrp_id; - - euser_id = geteuid(); - egrp_id = getegid(); - - /* find the block device file */ - - if ( sys_stat(path, &S) == -1 ) - return(False) ; - - devno = S.st_dev ; - - fp = setmntent(MOUNTED,"r"); - found = False ; - - while ((mnt = getmntent(fp))) { - if ( sys_stat(mnt->mnt_dir,&S) == -1 ) - continue ; - - if (S.st_dev == devno) { - found = True ; - break; - } - } - - endmntent(fp) ; - - if (!found) - return(False); - - save_re_uid(); - set_effective_uid(0); - - if (strcmp(mnt->mnt_type, "xfs")==0) { - r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - } else { - r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - if (r == -1 && errno != EDQUOT) { - r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - if (r == -1 && errno != EDQUOT) - r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - } - } - - restore_re_uid(); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - *bsize = D.bsize; - if (r == -1) { - if (errno == EDQUOT) { - *dfree =0; - *dsize =D.curblocks; - return (True); - } else { - return(False); - } - } - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (D.softlimit && D.curblocks >= D.softlimit) || - (D.hardlimit && D.curblocks >= D.hardlimit) || - (D.isoftlimit && D.curinodes >= D.isoftlimit) || - (D.ihardlimit && D.curinodes>=D.ihardlimit) - ) { - *dfree = 0; - *dsize = D.curblocks; - } else if (D.softlimit==0 && D.hardlimit==0) { - return(False); - } else { - if (D.softlimit == 0) - D.softlimit = D.hardlimit; - *dfree = D.softlimit - D.curblocks; - *dsize = D.softlimit; - } - - return (True); -} - -#elif defined(CRAY) - -#include <sys/quota.h> -#include <mntent.h> - -/**************************************************************************** -try to get the disk space from disk quotas (CRAY VERSION) -****************************************************************************/ - -BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - struct mntent *mnt; - FILE *fd; - SMB_STRUCT_STAT sbuf; - SMB_DEV_T devno ; - static SMB_DEV_T devno_cached = 0 ; - static pstring name; - struct q_request request ; - struct qf_header header ; - static int quota_default = 0 ; - int found ; - - if ( sys_stat(path,&sbuf) == -1 ) - return(False) ; - - devno = sbuf.st_dev ; - - if ( devno != devno_cached ) { - - devno_cached = devno ; - - if ((fd = setmntent(KMTAB)) == NULL) - return(False) ; - - found = False ; - - while ((mnt = getmntent(fd)) != NULL) { - - if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 ) - continue ; - - if (sbuf.st_dev == devno) { - - found = True ; - break ; - - } - - } - - pstrcpy(name,mnt->mnt_dir) ; - endmntent(fd) ; - - if ( ! found ) - return(False) ; - } - - request.qf_magic = QF_MAGIC ; - request.qf_entry.id = geteuid() ; - - if (quotactl(name, Q_GETQUOTA, &request) == -1) - return(False) ; - - if ( ! request.user ) - return(False) ; - - if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) { - - if ( ! quota_default ) { - - if ( quotactl(name, Q_GETHEADER, &header) == -1 ) - return(False) ; - else - quota_default = header.user_h.def_fq ; - } - - *dfree = quota_default ; - - }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) { - - *dfree = 0 ; - - }else{ - - *dfree = request.qf_entry.user_q.f_quota ; - - } - - *dsize = request.qf_entry.user_q.f_use ; - - if ( *dfree < *dsize ) - *dfree = 0 ; - else - *dfree -= *dsize ; - - *bsize = 4096 ; /* Cray blocksize */ - - return(True) ; - -} - - -#elif defined(SUNOS5) || defined(SUNOS4) - -#include <fcntl.h> -#include <sys/param.h> -#if defined(SUNOS5) -#include <sys/fs/ufs_quota.h> -#include <sys/mnttab.h> -#include <sys/mntent.h> -#else /* defined(SUNOS4) */ -#include <ufs/quota.h> -#include <mntent.h> -#endif - -#if defined(SUNOS5) - -/**************************************************************************** - Allows querying of remote hosts for quotas on NFS mounted shares. - Supports normal NFS and AMD mounts. - Alan Romeril <a.romeril@ic.ac.uk> July 2K. -****************************************************************************/ - -#include <rpc/rpc.h> -#include <rpc/types.h> -#include <rpcsvc/rquota.h> -#include <rpc/nettype.h> -#include <rpc/xdr.h> - -static int quotastat; - -static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args) -{ - if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN )) - return(0); - if (!xdr_int(xdrsp, &args->gqa_uid)) - return(0); - return (1); -} - -static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr) -{ - if (!xdr_int(xdrsp, "astat)) { - DEBUG(6,("nfs_quotas: Status bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) { - DEBUG(6,("nfs_quotas: Block size bad or zero\n")); - return 0; - } - if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) { - DEBUG(6,("nfs_quotas: Active bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) { - DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) { - DEBUG(6,("nfs_quotas: Softlimit bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) { - DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n")); - return 0; - } - return (1); -} - -/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ -static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - uid_t uid = euser_id; - struct dqblk D; - char *mnttype = nfspath; - CLIENT *clnt; - struct getquota_rslt gqr; - struct getquota_args args; - char *cutstr, *pathname, *host, *testpath; - int len; - static struct timeval timeout = {2,0}; - enum clnt_stat clnt_stat; - BOOL ret = True; - - *bsize = *dfree = *dsize = (SMB_BIG_UINT)0; - - len=strcspn(mnttype, ":"); - pathname=strstr(mnttype, ":"); - cutstr = (char *) malloc(len+1); - if (!cutstr) - return False; - - memset(cutstr, '\0', len+1); - host = strncat(cutstr,mnttype, sizeof(char) * len ); - DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr)); - DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype)); - testpath=strchr_m(mnttype, ':'); - args.gqa_pathp = testpath+1; - args.gqa_uid = uid; - - DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp")); - - if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) { - ret = False; - goto out; - } - - clnt->cl_auth = authunix_create_default(); - DEBUG(9,("nfs_quotas: auth_success\n")); - - clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout); - - if (clnt_stat != RPC_SUCCESS) { - DEBUG(9,("nfs_quotas: clnt_call fail\n")); - ret = False; - goto out; - } - - /* - * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is - * no quota set, and 3 if no permission to get the quota. If 0 or 3 return - * something sensible. - */ - - switch ( quotastat ) { - case 0: - DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat )); - ret = False; - goto out; - - case 1: - DEBUG(9,("nfs_quotas: Good quota data\n")); - D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit; - D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit; - D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks; - break; - - case 2: - case 3: - D.dqb_bsoftlimit = 1; - D.dqb_curblocks = 1; - DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat )); - break; - - default: - DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat )); - break; - } - - DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n", - quotastat, - gqr.getquota_rslt_u.gqr_rquota.rq_bsize, - gqr.getquota_rslt_u.gqr_rquota.rq_active, - gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit, - gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit, - gqr.getquota_rslt_u.gqr_rquota.rq_curblocks)); - - *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize; - *dsize = D.dqb_bsoftlimit; - - if (D.dqb_curblocks == D.dqb_curblocks == 1) - *bsize = 512; - - if (D.dqb_curblocks > D.dqb_bsoftlimit) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } else - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - - out: - - if (clnt) { - if (clnt->cl_auth) - auth_destroy(clnt->cl_auth); - clnt_destroy(clnt); - } - - DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize)); - - SAFE_FREE(cutstr); - DEBUG(10,("nfs_quotas: End of nfs_quotas\n" )); - return ret; -} -#endif - -/**************************************************************************** -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(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - uid_t euser_id; - int ret; - struct dqblk D; -#if defined(SUNOS5) - struct quotctl command; - int file; - static struct mnttab mnt; - static pstring name; - pstring devopt; -#else /* SunOS4 */ - struct mntent *mnt; - static pstring name; -#endif - FILE *fd; - SMB_STRUCT_STAT sbuf; - SMB_DEV_T devno ; - static SMB_DEV_T devno_cached = 0 ; - static int found ; - - euser_id = geteuid(); - - if ( sys_stat(path,&sbuf) == -1 ) - return(False) ; - - devno = sbuf.st_dev ; - DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno)); - if ( devno != devno_cached ) { - devno_cached = devno ; -#if defined(SUNOS5) - if ((fd = sys_fopen(MNTTAB, "r")) == NULL) - return(False) ; - - found = False ; - slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno); - while (getmntent(fd, &mnt) == 0) { - if( !hasmntopt(&mnt, devopt) ) - continue; - - DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt)); - - /* quotas are only on vxfs, UFS or NFS */ - if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 || - strcmp( mnt.mnt_fstype, "nfs" ) == 0 || - strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) { - found = True ; - break; - } - } - - pstrcpy(name,mnt.mnt_mountp) ; - pstrcat(name,"/quotas") ; - fclose(fd) ; -#else /* SunOS4 */ - if ((fd = setmntent(MOUNTED, "r")) == NULL) - return(False) ; - - found = False ; - while ((mnt = getmntent(fd)) != NULL) { - if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 ) - continue ; - DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev)); - if (sbuf.st_dev == devno) { - found = True ; - break; - } - } - - pstrcpy(name,mnt->mnt_fsname) ; - endmntent(fd) ; -#endif - } - - if ( ! found ) - return(False) ; - - save_re_uid(); - set_effective_uid(0); - -#if defined(SUNOS5) - if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) { - BOOL retval; - DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special)); - retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize); - restore_re_uid(); - return retval; - } - - DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); - if((file=sys_open(name, O_RDONLY,0))<0) { - restore_re_uid(); - return(False); - } - command.op = Q_GETQUOTA; - command.uid = euser_id; - command.addr = (caddr_t) &D; - ret = ioctl(file, Q_QUOTACTL, &command); - close(file); -#else - DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name)); - ret = quotactl(Q_GETQUOTA, name, euser_id, &D); -#endif - - restore_re_uid(); - - if (ret < 0) { - DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) )); - -#if defined(SUNOS5) && defined(VXFS_QUOTA) - /* If normal quotactl() fails, try vxfs private calls */ - set_effective_uid(euser_id); - DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype)); - if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) { - BOOL retval; - retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize); - return(retval); - } -#else - return(False); -#endif - } - - /* If softlimit is zero, set it equal to hardlimit. - */ - - if (D.dqb_bsoftlimit==0) - D.dqb_bsoftlimit = D.dqb_bhardlimit; - - /* Use softlimit to determine disk space. A user exceeding the quota is told - * that there's no space left. Writes might actually work for a bit if the - * hardlimit is set higher than softlimit. Effectively the disk becomes - * made of rubber latex and begins to expand to accommodate the user :-) - */ - - if (D.dqb_bsoftlimit==0) - return(False); - *bsize = DEV_BSIZE; - *dsize = D.dqb_bsoftlimit; - - if (D.dqb_curblocks > D.dqb_bsoftlimit) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } else - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - - DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", - path,(double)*bsize,(double)*dfree,(double)*dsize)); - - return(True); -} - - -#elif defined(OSF1) -#include <ufs/quota.h> - -/**************************************************************************** -try to get the disk space from disk quotas - OSF1 version -****************************************************************************/ - -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; - SMB_STRUCT_STAT S; - uid_t euser_id; - - /* - * This code presumes that OSF1 will only - * give out quota info when the real uid - * matches the effective uid. JRA. - */ - euser_id = geteuid(); - save_re_uid(); - if (set_re_uid() != 0) return False; - - r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D); - if (r) { - save_errno = errno; - } - - restore_re_uid(); - - *bsize = DEV_BSIZE; - - if (r) - { - if (save_errno == EDQUOT) /* disk quota exceeded */ - { - *dfree = 0; - *dsize = D.dqb_curblocks; - return (True); - } - else - return (False); - } - - /* If softlimit is zero, set it equal to hardlimit. - */ - - if (D.dqb_bsoftlimit==0) - D.dqb_bsoftlimit = D.dqb_bhardlimit; - - /* Use softlimit to determine disk space, except when it has been exceeded */ - - if (D.dqb_bsoftlimit==0) - return(False); - - if ((D.dqb_curblocks>D.dqb_bsoftlimit)) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} - -#elif defined (IRIX6) -/**************************************************************************** -try to get the disk space from disk quotas (IRIX 6.2 version) -****************************************************************************/ - -#include <sys/quota.h> -#include <mntent.h> - -BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - uid_t euser_id; - int r; - struct dqblk D; - struct fs_disk_quota F; - SMB_STRUCT_STAT S; - FILE *fp; - struct mntent *mnt; - SMB_DEV_T devno; - int found; - - /* find the block device file */ - - if ( sys_stat(path, &S) == -1 ) { - return(False) ; - } - - devno = S.st_dev ; - - fp = setmntent(MOUNTED,"r"); - found = False ; - - while ((mnt = getmntent(fp))) { - if ( sys_stat(mnt->mnt_dir,&S) == -1 ) - continue ; - if (S.st_dev == devno) { - found = True ; - break ; - } - } - endmntent(fp) ; - - if (!found) { - return(False); - } - - euser_id=geteuid(); - save_re_uid(); - set_effective_uid(0); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - - *bsize = 512; - - if ( 0 == strcmp ( mnt->mnt_type, "efs" )) - { - r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D); - - restore_re_uid(); - - if (r==-1) - return(False); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) || - (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) || - (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) || - (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit) - ) - { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0) - { - return(False); - } - else - { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - - } - else if ( 0 == strcmp ( mnt->mnt_type, "xfs" )) - { - r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F); - - restore_re_uid(); - - if (r==-1) - return(False); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) || - (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) || - (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) || - (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit) - ) - { - *dfree = 0; - *dsize = F.d_bcount; - } - else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0) - { - return(False); - } - else - { - *dfree = (F.d_blk_softlimit - F.d_bcount); - *dsize = F.d_blk_softlimit; - } - - } - else - { - restore_re_uid(); - return(False); - } - - return (True); - -} - -#else - -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#include <ufs/ufs/quota.h> -#include <machine/param.h> -#elif AIX -/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */ -#include <jfs/quota.h> -/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */ -#define dqb_curfiles dqb_curinodes -#define dqb_fhardlimit dqb_ihardlimit -#define dqb_fsoftlimit dqb_isoftlimit -#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */ -#include <sys/quota.h> -#include <devnm.h> -#endif - -/**************************************************************************** -try to get the disk space from disk quotas - default version -****************************************************************************/ - -BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - int r; - struct dqblk D; - uid_t euser_id; -#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) - char dev_disk[256]; - SMB_STRUCT_STAT S; - - /* find the block device file */ - -#ifdef HPUX - /* Need to set the cache flag to 1 for HPUX. Seems - * to have a significant performance boost when - * lstat calls on /dev access this function. - */ - if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0)) -#else - if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) - return (False); -#endif /* ifdef HPUX */ - -#endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */ - - euser_id = geteuid(); - -#ifdef HPUX - /* for HPUX, real uid must be same as euid to execute quotactl for euid */ - save_re_uid(); - if (set_re_uid() != 0) return False; - - r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); - - restore_re_uid(); -#else -#if defined(__FreeBSD__) || defined(__OpenBSD__) - { - /* FreeBSD patches from Marty Moll <martym@arbor.edu> */ - gid_t egrp_id; - - save_re_uid(); - set_effective_uid(0); - - egrp_id = getegid(); - r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); - - /* As FreeBSD has group quotas, if getting the user - quota fails, try getting the group instead. */ - if (r) { - r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D); - } - - restore_re_uid(); - } -#elif defined(AIX) - /* AIX has both USER and GROUP quotas: - Get the USER quota (ohnielse@fysik.dtu.dk) */ - save_re_uid(); - if (set_re_uid() != 0) - return False; - r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); - restore_re_uid(); -#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */ - r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); -#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */ -#endif /* HPUX */ - - /* Use softlimit to determine disk space, except when it has been exceeded */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) - *bsize = DEV_BSIZE; -#else /* !__FreeBSD__ && !__OpenBSD__ */ - *bsize = 1024; -#endif /*!__FreeBSD__ && !__OpenBSD__ */ - - if (r) - { - if (errno == EDQUOT) - { - *dfree =0; - *dsize =D.dqb_curblocks; - return (True); - } - else return(False); - } - - /* If softlimit is zero, set it equal to hardlimit. - */ - - if (D.dqb_bsoftlimit==0) - D.dqb_bsoftlimit = D.dqb_bhardlimit; - - if (D.dqb_bsoftlimit==0) - return(False); - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ((D.dqb_curblocks>D.dqb_bsoftlimit) -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) -||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0)) -#endif - ) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} - -#endif - -#if defined(VXFS_QUOTA) - -/**************************************************************************** -Try to get the disk space from Veritas disk quotas. - David Lee <T.D.Lee@durham.ac.uk> August 1999. - -Background assumptions: - Potentially under many Operating Systems. Initially Solaris 2. - - My guess is that Veritas is largely, though not entirely, - independent of OS. So I have separated it out. - - There may be some details. For example, OS-specific "include" files. - - It is understood that HPUX 10 somehow gets Veritas quotas without - any special effort; if so, this routine need not be compiled in. - Dirk De Wachter <Dirk.DeWachter@rug.ac.be> - -Warning: - It is understood that Veritas do not publicly support this ioctl interface. - Rather their preference would be for the user (us) to call the native - OS and then for the OS itself to call through to the VxFS filesystem. - Presumably HPUX 10, see above, does this. - -Hints for porting: - Add your OS to "IFLIST" below. - Get it to compile successfully: - Almost certainly "include"s require attention: see SUNOS5. - In the main code above, arrange for it to be called: see SUNOS5. - Test! - -****************************************************************************/ - -/* "IFLIST" - * This "if" is a list of ports: - * if defined(OS1) || defined(OS2) || ... - */ -#if defined(SUNOS5) - -#if defined(SUNOS5) -#include <sys/fs/vx_solaris.h> -#endif -#include <sys/fs/vx_machdep.h> -#include <sys/fs/vx_layout.h> -#include <sys/fs/vx_quota.h> -#include <sys/fs/vx_aioctl.h> -#include <sys/fs/vx_ioctl.h> - -BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - uid_t user_id, euser_id; - int ret; - struct vx_dqblk D; - struct vx_quotctl quotabuf; - struct vx_genioctl genbuf; - pstring qfname; - int file; - - /* - * "name" may or may not include a trailing "/quotas". - * Arranging consistency of calling here in "quotas.c" may not be easy and - * it might be easier to examine and adjust it here. - * Fortunately, VxFS seems not to mind at present. - */ - pstrcpy(qfname, name) ; - /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */ - - euser_id = geteuid(); - set_effective_uid(0); - - DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname)); - if((file=sys_open(qfname, O_RDONLY,0))<0) { - set_effective_uid(euser_id); - return(False); - } - genbuf.ioc_cmd = VX_QUOTACTL; - genbuf.ioc_up = (void *) "abuf; - - quotabuf.cmd = VX_GETQUOTA; - quotabuf.uid = euser_id; - quotabuf.addr = (caddr_t) &D; - ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf); - close(file); - - set_effective_uid(euser_id); - - if (ret < 0) { - DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) )); - return(False); - } - - /* If softlimit is zero, set it equal to hardlimit. - */ - - if (D.dqb_bsoftlimit==0) - D.dqb_bsoftlimit = D.dqb_bhardlimit; - - /* Use softlimit to determine disk space. A user exceeding the quota is told - * that there's no space left. Writes might actually work for a bit if the - * hardlimit is set higher than softlimit. Effectively the disk becomes - * made of rubber latex and begins to expand to accommodate the user :-) - */ - DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n", - path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit, - D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit)); - - if (D.dqb_bsoftlimit==0) - return(False); - *bsize = DEV_BSIZE; - *dsize = D.dqb_bsoftlimit; - - if (D.dqb_curblocks > D.dqb_bsoftlimit) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } else - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - - DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", - path,(double)*bsize,(double)*dfree,(double)*dsize)); - - return(True); -} - -#endif /* SUNOS5 || ... */ - -#endif /* VXFS_QUOTA */ - -#else /* WITH_QUOTAS */ - -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 */ - - /* And just to be sure we set some values that hopefully */ - /* will be larger that any possible real-world value */ - (*dfree) = (SMB_BIG_UINT)-1; - (*dsize) = (SMB_BIG_UINT)-1; - - /* As we have select not to use quotas, allways fail */ - return False; -} -#endif /* WITH_QUOTAS */ - -#else /* HAVE_SYS_QUOTAS */ -/* wrapper to the new sys_quota interface - this file should be removed later - */ -BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) -{ - int r; - SMB_DISK_QUOTA D; - unid_t id; - - id.uid = geteuid(); - - ZERO_STRUCT(D); - r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - *bsize = D.bsize; - if (r == -1) { - if (errno == EDQUOT) { - *dfree =0; - *dsize =D.curblocks; - return (True); - } else { - goto try_group_quota; - } - } - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (D.softlimit && D.curblocks >= D.softlimit) || - (D.hardlimit && D.curblocks >= D.hardlimit) || - (D.isoftlimit && D.curinodes >= D.isoftlimit) || - (D.ihardlimit && D.curinodes>=D.ihardlimit) - ) { - *dfree = 0; - *dsize = D.curblocks; - } else if (D.softlimit==0 && D.hardlimit==0) { - goto try_group_quota; - } else { - if (D.softlimit == 0) - D.softlimit = D.hardlimit; - *dfree = D.softlimit - D.curblocks; - *dsize = D.softlimit; - } - - return True; - -try_group_quota: - id.gid = getegid(); - - ZERO_STRUCT(D); - r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - *bsize = D.bsize; - if (r == -1) { - if (errno == EDQUOT) { - *dfree =0; - *dsize =D.curblocks; - return (True); - } else { - return False; - } - } - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (D.softlimit && D.curblocks >= D.softlimit) || - (D.hardlimit && D.curblocks >= D.hardlimit) || - (D.isoftlimit && D.curinodes >= D.isoftlimit) || - (D.ihardlimit && D.curinodes>=D.ihardlimit) - ) { - *dfree = 0; - *dsize = D.curblocks; - } else if (D.softlimit==0 && D.hardlimit==0) { - return False; - } else { - if (D.softlimit == 0) - D.softlimit = D.hardlimit; - *dfree = D.softlimit - D.curblocks; - *dsize = D.softlimit; - } - - return (True); -} -#endif /* HAVE_SYS_QUOTAS */ diff --git a/source/smbd/reply.c b/source/smbd/reply.c deleted file mode 100644 index ac239c7e042..00000000000 --- a/source/smbd/reply.c +++ /dev/null @@ -1,4974 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Main SMB reply routines - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 1992-2004. - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This file handles most of the reply_ calls that the server - makes to handle specific protocols -*/ - -#include "includes.h" - -/* look in server.c for some explanation of these variables */ -extern int Protocol; -extern int max_send; -extern int max_recv; -extern char magic_char; -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL short_case_preserve; -extern int global_oplock_break; -unsigned int smb_echo_count = 0; - -extern BOOL global_encrypted_passwords_negotiated; - -/**************************************************************************** - Ensure we check the path in *exactly* the same way as W2K. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). '\\' *may* be the second byte in a multibyte char - set. -****************************************************************************/ - -NTSTATUS check_path_syntax(pstring destname, const pstring srcname) -{ - char *d = destname; - const char *s = srcname; - NTSTATUS ret = NT_STATUS_OK; - - while (*s) { - if (IS_DIRECTORY_SEP(*s)) { - /* - * Safe to assume is not the second part of a mb char as this is handled below. - */ - /* Eat multiple '/' or '\\' */ - while (IS_DIRECTORY_SEP(*s)) { - s++; - } - if ((s[0] == '.') && (s[1] == '\0')) { - ret = NT_STATUS_OBJECT_NAME_INVALID; - break; - } - if ((d != destname) && (*s != '\0')) { - /* We only care about non-leading or trailing '/' or '\\' */ - *d++ = '/'; - } - } else if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) { - /* Uh oh - "../" or "..\\" or "..\0" ! */ - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* If we just added a '/', delete it. */ - - if ((d > destname) && (*(d-1) == '/')) { - *(d-1) = '\0'; - if (d == (destname + 1)) { - d--; - } else { - d -= 2; - } - } - /* Are we at the start ? Can't go back further if so. */ - if (d == destname) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; - } - /* Go back one level... */ - /* We know this is safe as '/' cannot be part of a mb sequence. */ - /* NOTE - if this assumption is invalid we are not in good shape... */ - while (d > destname) { - if (*d == '/') - break; - d--; - } - s += 3; - } else if ((s[0] == '.') && (IS_DIRECTORY_SEP(s[1]) || (s[1] == '\0'))) { - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* "./" or ".\\" fails with a different error depending on where it is... */ - - if (s == srcname) { - ret = NT_STATUS_OBJECT_NAME_INVALID; - break; - } else { - if (s[1] != '\0' && s[2] == '\0') { - ret = NT_STATUS_INVALID_PARAMETER; - break; - } - ret = NT_STATUS_OBJECT_PATH_NOT_FOUND; - break; - } - s++; - } else { - if (!(*s & 0x80)) { - *d++ = *s++; - } else { - switch(next_mb_char_size(s)) { - case 4: - *d++ = *s++; - case 3: - *d++ = *s++; - case 2: - *d++ = *s++; - case 1: - *d++ = *s++; - break; - default: - DEBUG(0,("check_path_syntax: character length assumptions invalid !\n")); - *d = '\0'; - return NT_STATUS_INVALID_PARAMETER; - } - } - } - } - *d = '\0'; - return ret; -} - -/**************************************************************************** - Pull a string and check the path - provide for error return. -****************************************************************************/ - -size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err) -{ - pstring tmppath; - char *tmppath_ptr = tmppath; - size_t ret; -#ifdef DEVELOPER - SMB_ASSERT(dest_len == sizeof(pstring)); -#endif - - if (src_len == 0) { - ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags); - } else { - ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags); - } - *err = check_path_syntax(dest, tmppath); - return ret; -} - -/**************************************************************************** - Reply to a special message. -****************************************************************************/ - -int reply_special(char *inbuf,char *outbuf) -{ - int outsize = 4; - int msg_type = CVAL(inbuf,0); - int msg_flags = CVAL(inbuf,1); - fstring name1,name2; - char name_type = 0; - - static BOOL already_got_session = False; - - *name1 = *name2 = 0; - - memset(outbuf,'\0',smb_size); - - smb_setlen(outbuf,0); - - switch (msg_type) { - case 0x81: /* session request */ - - if (already_got_session) { - exit_server("multiple session request not permitted"); - } - - 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")); - return(0); - } - name_extract(inbuf,4,name1); - name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2); - DEBUG(2,("netbios connect: name1=%s name2=%s\n", - name1,name2)); - - set_local_machine_name(name1, True); - set_remote_machine_name(name2, True); - - DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n", - get_local_machine_name(), get_remote_machine_name(), - name_type)); - - if (name_type == 'R') { - /* We are being asked for a pathworks session --- - no thanks! */ - SCVAL(outbuf, 0,0x83); - break; - } - - /* only add the client's machine name to the list - of possibly valid usernames if we are operating - in share mode security */ - if (lp_security() == SEC_SHARE) { - add_session_user(get_remote_machine_name()); - } - - reload_services(True); - reopen_logs(); - - claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD); - - already_got_session = True; - break; - - case 0x89: /* session keepalive request - (some old clients produce this?) */ - SCVAL(outbuf,0,SMBkeepalive); - SCVAL(outbuf,3,0); - break; - - case 0x82: /* positive session response */ - case 0x83: /* negative session response */ - case 0x84: /* retarget session response */ - DEBUG(0,("Unexpected session response\n")); - break; - - case SMBkeepalive: /* session keepalive */ - default: - return(0); - } - - DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n", - msg_type, msg_flags)); - - return(outsize); -} - -/**************************************************************************** - Reply to a tcon. -****************************************************************************/ - -int reply_tcon(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - const char *service; - pstring service_buf; - pstring password; - pstring dev; - int outsize = 0; - uint16 vuid = SVAL(inbuf,smb_uid); - int pwlen=0; - NTSTATUS nt_status; - char *p; - DATA_BLOB password_blob; - - START_PROFILE(SMBtcon); - - *service_buf = *password = *dev = 0; - - p = smb_buf(inbuf)+1; - p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service_buf), STR_TERMINATE) + 1; - pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1; - p += pwlen; - p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1; - - p = strrchr_m(service_buf,'\\'); - if (p) { - service = p+1; - } else { - service = service_buf; - } - - password_blob = data_blob(password, pwlen+1); - - conn = make_connection(service,password_blob,dev,vuid,&nt_status); - - data_blob_clear_free(&password_blob); - - if (!conn) { - END_PROFILE(SMBtcon); - return ERROR_NT(nt_status); - } - - outsize = set_message(outbuf,2,0,True); - SSVAL(outbuf,smb_vwv0,max_recv); - SSVAL(outbuf,smb_vwv1,conn->cnum); - SSVAL(outbuf,smb_tid,conn->cnum); - - DEBUG(3,("tcon service=%s cnum=%d\n", - service, conn->cnum)); - - END_PROFILE(SMBtcon); - return(outsize); -} - -/**************************************************************************** - Reply to a tcon and X. -****************************************************************************/ - -int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - fstring service; - DATA_BLOB password; - - /* what the cleint thinks the device is */ - fstring client_devicetype; - /* what the server tells the client the share represents */ - const char *server_devicetype; - NTSTATUS nt_status; - uint16 vuid = SVAL(inbuf,smb_uid); - int passlen = SVAL(inbuf,smb_vwv3); - pstring path; - char *p, *q; - extern BOOL global_encrypted_passwords_negotiated; - - START_PROFILE(SMBtconX); - - *service = *client_devicetype = 0; - - /* we might have to close an old one */ - if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) { - close_cnum(conn,vuid); - } - - if (passlen > MAX_PASS_LEN) { - return ERROR_DOS(ERRDOS,ERRbuftoosmall); - } - - if (global_encrypted_passwords_negotiated) { - password = data_blob(smb_buf(inbuf),passlen); - } else { - password = data_blob(smb_buf(inbuf),passlen+1); - /* Ensure correct termination */ - password.data[passlen]=0; - } - - p = smb_buf(inbuf) + passlen; - p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE); - - /* - * the service name can be either: \\server\share - * or share directly like on the DELL PowerVault 705 - */ - if (*path=='\\') { - q = strchr_m(path+2,'\\'); - if (!q) { - END_PROFILE(SMBtconX); - return(ERROR_DOS(ERRDOS,ERRnosuchshare)); - } - fstrcpy(service,q+1); - } - else - fstrcpy(service,path); - - p += srvstr_pull(inbuf, client_devicetype, p, sizeof(client_devicetype), 6, STR_ASCII); - - DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service)); - - conn = make_connection(service,password,client_devicetype,vuid,&nt_status); - - data_blob_clear_free(&password); - - if (!conn) { - END_PROFILE(SMBtconX); - return ERROR_NT(nt_status); - } - - if ( IS_IPC(conn) ) - server_devicetype = "IPC"; - else if ( IS_PRINT(conn) ) - server_devicetype = "LPT1:"; - else - server_devicetype = "A:"; - - if (Protocol < PROTOCOL_NT1) { - set_message(outbuf,2,0,True); - p = smb_buf(outbuf); - p += srvstr_push(outbuf, p, server_devicetype, -1, - STR_TERMINATE|STR_ASCII); - set_message_end(outbuf,p); - } else { - /* NT sets the fstype of IPC$ to the null string */ - const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn)); - - set_message(outbuf,3,0,True); - - p = smb_buf(outbuf); - p += srvstr_push(outbuf, p, server_devicetype, -1, - STR_TERMINATE|STR_ASCII); - p += srvstr_push(outbuf, p, fstype, -1, - STR_TERMINATE); - - set_message_end(outbuf,p); - - /* what does setting this bit do? It is set by NT4 and - may affect the ability to autorun mounted cdroms */ - SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS| - (lp_csc_policy(SNUM(conn)) << 2)); - - init_dfsroot(conn, inbuf, outbuf); - } - - - DEBUG(3,("tconX service=%s \n", - service)); - - /* set the incoming and outgoing tid to the just created one */ - SSVAL(inbuf,smb_tid,conn->cnum); - SSVAL(outbuf,smb_tid,conn->cnum); - - END_PROFILE(SMBtconX); - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - Reply to an unknown type. -****************************************************************************/ - -int reply_unknown(char *inbuf,char *outbuf) -{ - int type; - type = CVAL(inbuf,smb_com); - - DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n", - smb_fn_name(type), type, type)); - - return(ERROR_DOS(ERRSRV,ERRunknownsmb)); -} - -/**************************************************************************** - Reply to an ioctl. -****************************************************************************/ - -int reply_ioctl(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - uint16 device = SVAL(inbuf,smb_vwv1); - uint16 function = SVAL(inbuf,smb_vwv2); - uint32 ioctl_code = (device << 16) + function; - int replysize, outsize; - char *p; - START_PROFILE(SMBioctl); - - DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code)); - - switch (ioctl_code) { - case IOCTL_QUERY_JOB_INFO: - replysize = 32; - break; - default: - END_PROFILE(SMBioctl); - return(ERROR_DOS(ERRSRV,ERRnosupport)); - } - - outsize = set_message(outbuf,8,replysize+1,True); - SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */ - SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */ - SSVAL(outbuf,smb_vwv6,52); /* Offset to data */ - p = smb_buf(outbuf) + 1; /* Allow for alignment */ - - switch (ioctl_code) { - case IOCTL_QUERY_JOB_INFO: - { - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - if (!fsp) { - END_PROFILE(SMBioctl); - return(UNIXERROR(ERRDOS,ERRbadfid)); - } - SSVAL(p,0,fsp->rap_print_jobid); /* Job number */ - srvstr_push(outbuf, p+2, global_myname(), 15, STR_TERMINATE|STR_ASCII); - srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); - break; - } - } - - END_PROFILE(SMBioctl); - return outsize; -} - -/**************************************************************************** - Reply to a chkpth. -****************************************************************************/ - -int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - int mode; - pstring name; - BOOL ok = False; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - NTSTATUS status; - - START_PROFILE(SMBchkpth); - - srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBchkpth); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - - unix_convert(name,conn,0,&bad_path,&sbuf); - - mode = SVAL(inbuf,smb_vwv0); - - if (check_name(name,conn)) { - if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0) - if (!(ok = S_ISDIR(sbuf.st_mode))) { - END_PROFILE(SMBchkpth); - return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath); - } - } - - 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) { - /* - * Windows returns different error codes if - * the parent directory is valid but not the - * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND - * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND - * if the path is invalid. - */ - if (bad_path) { - END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } else { - END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND); - } - } else if (errno == ENOTDIR) { - END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY); - } - - END_PROFILE(SMBchkpth); - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("chkpth %s mode=%d\n", name, mode)); - - END_PROFILE(SMBchkpth); - return(outsize); -} - -/**************************************************************************** - Reply to a getatr. -****************************************************************************/ - -int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring fname; - int outsize = 0; - SMB_STRUCT_STAT sbuf; - BOOL ok = False; - int mode=0; - SMB_OFF_T size=0; - time_t mtime=0; - BOOL bad_path = False; - char *p; - NTSTATUS status; - - START_PROFILE(SMBgetatr); - - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBgetatr); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - /* dos smetimes asks for a stat of "" - it returns a "hidden directory" - under WfWg - weird! */ - if (! (*fname)) { - mode = aHIDDEN | aDIR; - if (!CAN_WRITE(conn)) - mode |= aRONLY; - size = 0; - mtime = 0; - ok = True; - } else { - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (check_name(fname,conn)) { - if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) { - mode = dos_mode(conn,fname,&sbuf); - size = sbuf.st_size; - mtime = sbuf.st_mtime; - if (mode & aDIR) - size = 0; - ok = True; - } else { - DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno))); - } - } - } - - if (!ok) { - END_PROFILE(SMBgetatr); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadfile); - } - - outsize = set_message(outbuf,10,0,True); - - SSVAL(outbuf,smb_vwv0,mode); - if(lp_dos_filetime_resolution(SNUM(conn)) ) - put_dos_date3(outbuf,smb_vwv1,mtime & ~1); - else - put_dos_date3(outbuf,smb_vwv1,mtime); - SIVAL(outbuf,smb_vwv3,(uint32)size); - - if (Protocol >= PROTOCOL_NT1) - SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); - - DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) ); - - END_PROFILE(SMBgetatr); - return(outsize); -} - -/**************************************************************************** - Reply to a setatr. -****************************************************************************/ - -int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring fname; - int outsize = 0; - BOOL ok=False; - int mode; - time_t mtime; - SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; - char *p; - NTSTATUS status; - - START_PROFILE(SMBsetatr); - - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBsetatr); - return ERROR_NT(status); - } - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - mode = SVAL(inbuf,smb_vwv0); - mtime = make_unix_date3(inbuf+smb_vwv1); - - if (mode != FILE_ATTRIBUTE_NORMAL) { - if (VALID_STAT_OF_DIR(sbuf)) - mode |= aDIR; - else - mode &= ~aDIR; - - if (check_name(fname,conn)) { - ok = (file_set_dosmode(conn,fname,mode,NULL) == 0); - } - } else { - ok = True; - } - - if (ok) - ok = set_filetime(conn,fname,mtime); - - if (!ok) { - END_PROFILE(SMBsetatr); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) ); - - END_PROFILE(SMBsetatr); - return(outsize); -} - -/**************************************************************************** - Reply to a dskattr. -****************************************************************************/ - -int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - SMB_BIG_UINT dfree,dsize,bsize; - START_PROFILE(SMBdskattr); - - SMB_VFS_DISK_FREE(conn,".",True,&bsize,&dfree,&dsize); - - outsize = set_message(outbuf,5,0,True); - - if (Protocol <= PROTOCOL_LANMAN2) { - double total_space, free_space; - /* we need to scale this to a number that DOS6 can handle. We - use floating point so we can handle large drives on systems - that don't have 64 bit integers - - we end up displaying a maximum of 2G to DOS systems - */ - total_space = dsize * (double)bsize; - free_space = dfree * (double)bsize; - - dsize = (total_space+63*512) / (64*512); - dfree = (free_space+63*512) / (64*512); - - if (dsize > 0xFFFF) dsize = 0xFFFF; - if (dfree > 0xFFFF) dfree = 0xFFFF; - - SSVAL(outbuf,smb_vwv0,dsize); - SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */ - SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */ - SSVAL(outbuf,smb_vwv3,dfree); - } else { - SSVAL(outbuf,smb_vwv0,dsize); - SSVAL(outbuf,smb_vwv1,bsize/512); - SSVAL(outbuf,smb_vwv2,512); - SSVAL(outbuf,smb_vwv3,dfree); - } - - DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree)); - - END_PROFILE(SMBdskattr); - return(outsize); -} - -/**************************************************************************** - Reply to a search. - Can be called from SMBsearch, SMBffirst or SMBfunique. -****************************************************************************/ - -int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring mask; - pstring directory; - pstring fname; - SMB_OFF_T size; - int mode; - time_t date; - int dirtype; - int outsize = 0; - unsigned int numentries = 0; - unsigned int maxentries = 0; - BOOL finished = False; - char *p; - BOOL ok = False; - int status_len; - pstring path; - char status[21]; - int dptr_num= -1; - BOOL check_descend = False; - BOOL expect_close = False; - BOOL can_open = True; - BOOL bad_path = False; - NTSTATUS nt_status; - START_PROFILE(SMBsearch); - - *mask = *directory = *fname = 0; - - /* If we were called as SMBffirst then we must expect close. */ - if(CVAL(inbuf,smb_com) == SMBffirst) - expect_close = True; - - outsize = set_message(outbuf,1,3,True); - maxentries = SVAL(inbuf,smb_vwv0); - dirtype = SVAL(inbuf,smb_vwv1); - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status); - if (!NT_STATUS_IS_OK(nt_status)) { - END_PROFILE(SMBsearch); - return ERROR_NT(nt_status); - } - p++; - status_len = SVAL(p, 0); - p += 2; - - /* dirtype &= ~aDIR; */ - - if (status_len == 0) { - SMB_STRUCT_STAT sbuf; - pstring dir2; - - pstrcpy(directory,path); - pstrcpy(dir2,path); - unix_convert(directory,conn,0,&bad_path,&sbuf); - unix_format(dir2); - - if (!check_name(directory,conn)) - can_open = False; - - p = strrchr_m(dir2,'/'); - if (p == NULL) { - pstrcpy(mask,dir2); - *dir2 = 0; - } else { - *p = 0; - pstrcpy(mask,p+1); - } - - p = strrchr_m(directory,'/'); - if (!p) - *directory = 0; - else - *p = 0; - - if (strlen(directory) == 0) - pstrcpy(directory,"."); - memset((char *)status,'\0',21); - SCVAL(status,0,(dirtype & 0x1F)); - } else { - int status_dirtype; - - memcpy(status,p,21); - status_dirtype = CVAL(status,0) & 0x1F; - if (status_dirtype != (dirtype & 0x1F)) - dirtype = status_dirtype; - - conn->dirptr = dptr_fetch(status+12,&dptr_num); - if (!conn->dirptr) - goto SearchEmpty; - string_set(&conn->dirpath,dptr_path(dptr_num)); - pstrcpy(mask, dptr_wcard(dptr_num)); - } - - if (can_open) { - p = smb_buf(outbuf) + 3; - ok = True; - - if (status_len == 0) { - dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid)); - if (dptr_num < 0) { - if(dptr_num == -2) { - END_PROFILE(SMBsearch); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnofids); - } - END_PROFILE(SMBsearch); - return ERROR_DOS(ERRDOS,ERRnofids); - } - dptr_set_wcard(dptr_num, strdup(mask)); - dptr_set_attr(dptr_num, dirtype); - } else { - dirtype = dptr_attr(dptr_num); - } - - DEBUG(4,("dptr_num is %d\n",dptr_num)); - - if (ok) { - if ((dirtype&0x1F) == aVOLID) { - memcpy(p,status,21); - make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0); - dptr_fill(p+12,dptr_num); - if (dptr_zero(p+12) && (status_len==0)) - numentries = 1; - else - numentries = 0; - p += DIR_STRUCT_SIZE; - } else { - unsigned int i; - maxentries = MIN(maxentries, ((BUFFER_SIZE - (p - outbuf))/DIR_STRUCT_SIZE)); - - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True)) - check_descend = True; - - for (i=numentries;(i<maxentries) && !finished;i++) { - finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend); - if (!finished) { - memcpy(p,status,21); - make_dir_struct(p,mask,fname,size,mode,date); - dptr_fill(p+12,dptr_num); - numentries++; - } - p += DIR_STRUCT_SIZE; - } - } - } /* if (ok ) */ - } - - - SearchEmpty: - - /* If we were called as SMBffirst with smb_search_id == NULL - and no entries were found then return error and close dirptr - (X/Open spec) */ - - if(ok && expect_close && numentries == 0 && status_len == 0) { - if (Protocol < PROTOCOL_NT1) { - SCVAL(outbuf,smb_rcls,ERRDOS); - SSVAL(outbuf,smb_err,ERRnofiles); - } - /* Also close the dptr - we know it's gone */ - dptr_close(&dptr_num); - } else if (numentries == 0 || !ok) { - if (Protocol < PROTOCOL_NT1) { - SCVAL(outbuf,smb_rcls,ERRDOS); - SSVAL(outbuf,smb_err,ERRnofiles); - } - dptr_close(&dptr_num); - } - - /* If we were called as SMBfunique, then we can close the dirptr now ! */ - if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique) - dptr_close(&dptr_num); - - SSVAL(outbuf,smb_vwv0,numentries); - SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE); - SCVAL(smb_buf(outbuf),0,5); - SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE); - - if (Protocol >= PROTOCOL_NT1) - SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); - - outsize += DIR_STRUCT_SIZE*numentries; - smb_setlen(outbuf,outsize - 4); - - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - - DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%u of %u\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries, maxentries ) ); - - END_PROFILE(SMBsearch); - return(outsize); -} - -/**************************************************************************** - Reply to a fclose (stop directory search). -****************************************************************************/ - -int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - int status_len; - pstring path; - char status[21]; - int dptr_num= -2; - char *p; - NTSTATUS err; - - START_PROFILE(SMBfclose); - - outsize = set_message(outbuf,1,0,True); - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err); - if (!NT_STATUS_IS_OK(err)) { - END_PROFILE(SMBfclose); - return ERROR_NT(err); - } - p++; - status_len = SVAL(p,0); - p += 2; - - if (status_len == 0) { - END_PROFILE(SMBfclose); - return ERROR_DOS(ERRSRV,ERRsrverror); - } - - memcpy(status,p,21); - - if(dptr_fetch(status+12,&dptr_num)) { - /* Close the dptr - we know it's gone */ - dptr_close(&dptr_num); - } - - SSVAL(outbuf,smb_vwv0,0); - - DEBUG(3,("search close\n")); - - END_PROFILE(SMBfclose); - return(outsize); -} - -/**************************************************************************** - Reply to an open. -****************************************************************************/ - -int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring fname; - int outsize = 0; - int fmode=0; - int share_mode; - SMB_OFF_T size = 0; - time_t mtime=0; - int rmode=0; - SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - uint16 dos_attr = SVAL(inbuf,smb_vwv1); - NTSTATUS status; - START_PROFILE(SMBopen); - - share_mode = SVAL(inbuf,smb_vwv0); - - srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBopen); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - (uint32)dos_attr, oplock_request,&rmode,NULL); - - if (!fsp) { - END_PROFILE(SMBopen); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); - } - - size = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - mtime = sbuf.st_mtime; - - if (fmode & aDIR) { - DEBUG(3,("attempt to open a directory %s\n",fname)); - close_file(fsp,False); - END_PROFILE(SMBopen); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - outsize = set_message(outbuf,7,0,True); - SSVAL(outbuf,smb_vwv0,fsp->fnum); - SSVAL(outbuf,smb_vwv1,fmode); - if(lp_dos_filetime_resolution(SNUM(conn)) ) - put_dos_date3(outbuf,smb_vwv2,mtime & ~1); - else - put_dos_date3(outbuf,smb_vwv2,mtime); - SIVAL(outbuf,smb_vwv4,(uint32)size); - SSVAL(outbuf,smb_vwv6,rmode); - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); - - if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); - END_PROFILE(SMBopen); - return(outsize); -} - -/**************************************************************************** - Reply to an open and X. -****************************************************************************/ - -int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - pstring fname; - int smb_mode = SVAL(inbuf,smb_vwv3); - int smb_attr = SVAL(inbuf,smb_vwv5); - /* Breakout the oplock request bits so we can set the - reply bits separately. */ - BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf); - BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf); - BOOL oplock_request = ex_oplock_request | core_oplock_request; -#if 0 - int open_flags = SVAL(inbuf,smb_vwv2); - int smb_sattr = SVAL(inbuf,smb_vwv4); - uint32 smb_time = make_unix_date3(inbuf+smb_vwv6); -#endif - int smb_ofun = SVAL(inbuf,smb_vwv8); - SMB_OFF_T size=0; - int fmode=0,mtime=0,rmode=0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp; - NTSTATUS status; - START_PROFILE(SMBopenX); - - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - if (lp_nt_pipe_support()) { - END_PROFILE(SMBopenX); - return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize); - } else { - END_PROFILE(SMBopenX); - return ERROR_DOS(ERRSRV,ERRaccess); - } - } - - /* XXXX we need to handle passed times, sattr and flags */ - srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBopenX); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr, - oplock_request, &rmode,&smb_action); - - if (!fsp) { - END_PROFILE(SMBopenX); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); - } - - size = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - mtime = sbuf.st_mtime; - if (fmode & aDIR) { - close_file(fsp,False); - END_PROFILE(SMBopenX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* If the caller set the extended oplock request bit - and we granted one (by whatever means) - set the - correct bit for extended oplock reply. - */ - - if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) - smb_action |= EXTENDED_OPLOCK_GRANTED; - - if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - smb_action |= EXTENDED_OPLOCK_GRANTED; - - /* If the caller set the core oplock request bit - and we granted one (by whatever means) - set the - correct bit for core oplock reply. - */ - - if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); - - if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); - - set_message(outbuf,15,0,True); - SSVAL(outbuf,smb_vwv2,fsp->fnum); - SSVAL(outbuf,smb_vwv3,fmode); - if(lp_dos_filetime_resolution(SNUM(conn)) ) - put_dos_date3(outbuf,smb_vwv4,mtime & ~1); - else - put_dos_date3(outbuf,smb_vwv4,mtime); - SIVAL(outbuf,smb_vwv6,(uint32)size); - SSVAL(outbuf,smb_vwv8,rmode); - SSVAL(outbuf,smb_vwv11,smb_action); - - END_PROFILE(SMBopenX); - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - Reply to a SMBulogoffX. -****************************************************************************/ - -int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - uint16 vuid = SVAL(inbuf,smb_uid); - user_struct *vuser = get_valid_user_struct(vuid); - START_PROFILE(SMBulogoffX); - - if(vuser == 0) - DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid)); - - /* in user level security we are supposed to close any files - open by this user */ - if ((vuser != 0) && (lp_security() != SEC_SHARE)) - file_close_user(vuid); - - invalidate_vuid(vuid); - - set_message(outbuf,2,0,True); - - DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) ); - - END_PROFILE(SMBulogoffX); - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - Reply to a mknew or a create. -****************************************************************************/ - -int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring fname; - int com; - int outsize = 0; - int createmode; - int ofun = 0; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - SMB_STRUCT_STAT sbuf; - NTSTATUS status; - START_PROFILE(SMBcreate); - - com = SVAL(inbuf,smb_com); - - createmode = SVAL(inbuf,smb_vwv0); - srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBcreate); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - if (createmode & aVOLID) - DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname)); - - if(com == SMBmknew) { - /* We should fail if file exists. */ - ofun = FILE_CREATE_IF_NOT_EXIST; - } else { - /* SMBcreate - Create if file doesn't exist, truncate if it does. */ - ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE; - } - - /* Open file in dos compatibility share mode. */ - fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), - ofun, (uint32)createmode, oplock_request, NULL, NULL); - - if (!fsp) { - END_PROFILE(SMBcreate); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); - } - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,fsp->fnum); - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); - - if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - 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\n", fname, fsp->fd, createmode ) ); - - END_PROFILE(SMBcreate); - return(outsize); -} - -/**************************************************************************** - Reply to a create temporary file. -****************************************************************************/ - -int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring fname; - int outsize = 0; - int createattr; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - int tmpfd; - SMB_STRUCT_STAT sbuf; - char *p, *s; - NTSTATUS status; - unsigned int namelen; - - START_PROFILE(SMBctemp); - - createattr = SVAL(inbuf,smb_vwv0); - srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBctemp); - return ERROR_NT(status); - } - if (*fname) { - pstrcat(fname,"/TMXXXXXX"); - } else { - pstrcat(fname,"TMXXXXXX"); - } - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - tmpfd = smb_mkstemp(fname); - if (tmpfd == -1) { - END_PROFILE(SMBctemp); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - SMB_VFS_STAT(conn,fname,&sbuf); - - /* Open file in dos compatibility share mode. */ - /* We should fail if file does not exist. */ - fsp = open_file_shared(conn,fname,&sbuf, - SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), - FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST, - (uint32)createattr, oplock_request, NULL, NULL); - - /* close fd from smb_mkstemp() */ - close(tmpfd); - - if (!fsp) { - END_PROFILE(SMBctemp); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); - } - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,fsp->fnum); - - /* the returned filename is relative to the directory */ - s = strrchr_m(fname, '/'); - if (!s) - s = fname; - else - s++; - - p = smb_buf(outbuf); -#if 0 - /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only - thing in the byte section. JRA */ - SSVALS(p, 0, -1); /* what is this? not in spec */ -#endif - namelen = srvstr_push(outbuf, p, s, -1, STR_ASCII|STR_TERMINATE); - p += namelen; - outsize = set_message_end(outbuf, p); - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); - - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - 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 umode=%o\n", - fname, fsp->fd, sbuf.st_mode ) ); - - END_PROFILE(SMBctemp); - return(outsize); -} - -/******************************************************************* - Check if a user is allowed to rename a file. -********************************************************************/ - -static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst) -{ - int smb_action; - int access_mode; - files_struct *fsp; - - if (!CAN_WRITE(conn)) - return NT_STATUS_MEDIA_WRITE_PROTECTED; - - if (S_ISDIR(pst->st_mode)) - return NT_STATUS_OK; - - /* We need a better way to return NT status codes from open... */ - unix_ERR_class = 0; - unix_ERR_code = 0; - - fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action); - - if (!fsp) { - NTSTATUS ret = NT_STATUS_ACCESS_DENIED; - if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) - ret = NT_STATUS_SHARING_VIOLATION; - unix_ERR_class = 0; - unix_ERR_code = 0; - unix_ERR_ntstatus = NT_STATUS_OK; - return ret; - } - close_file(fsp,False); - return NT_STATUS_OK; -} - -/******************************************************************* - Check if a user is allowed to delete a file. -********************************************************************/ - -static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOOL bad_path) -{ - SMB_STRUCT_STAT sbuf; - int fmode; - int smb_action; - int access_mode; - files_struct *fsp; - - DEBUG(10,("can_delete: %s, dirtype = %d\n", - fname, dirtype )); - - if (!CAN_WRITE(conn)) - return NT_STATUS_MEDIA_WRITE_PROTECTED; - - if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) { - if(errno == ENOENT) { - if (bad_path) - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - else - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - return map_nt_error_from_unix(errno); - } - - fmode = dos_mode(conn,fname,&sbuf); - - /* Can't delete a directory. */ - if (fmode & aDIR) - return NT_STATUS_FILE_IS_A_DIRECTORY; -#if 0 /* JRATEST */ - else if (dirtype & aDIR) /* Asked for a directory and it isn't. */ - return NT_STATUS_OBJECT_NAME_INVALID; -#endif /* JRATEST */ - - if (!lp_delete_readonly(SNUM(conn))) { - if (fmode & aRONLY) - return NT_STATUS_CANNOT_DELETE; - } - if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) - return NT_STATUS_NO_SUCH_FILE; - - /* We need a better way to return NT status codes from open... */ - unix_ERR_class = 0; - unix_ERR_code = 0; - - fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action); - - if (!fsp) { - NTSTATUS ret = NT_STATUS_ACCESS_DENIED; - if (!NT_STATUS_IS_OK(unix_ERR_ntstatus)) - ret = unix_ERR_ntstatus; - else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) - ret = NT_STATUS_SHARING_VIOLATION; - unix_ERR_class = 0; - unix_ERR_code = 0; - unix_ERR_ntstatus = NT_STATUS_OK; - return ret; - } - close_file(fsp,False); - return NT_STATUS_OK; -} - -/**************************************************************************** - The guts of the unlink command, split out so it may be called by the NT SMB - code. -****************************************************************************/ - -NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) -{ - pstring directory; - pstring mask; - char *p; - int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL has_wild; - BOOL bad_path = False; - BOOL rc = True; - SMB_STRUCT_STAT sbuf; - - *directory = *mask = 0; - - /* We must check for wildcards in the name given - * directly by the client - before any unmangling. - * This prevents an unmangling of a UNIX name containing - * a DOS wildcard like '*' or '?' from unmangling into - * a wildcard delete which was not intended. - * FIX for #226. JRA. - */ - - has_wild = ms_has_wild(name); - - rc = unix_convert(name,conn,0,&bad_path,&sbuf); - - p = strrchr_m(name,'/'); - if (!p) { - pstrcpy(directory,"."); - pstrcpy(mask,name); - } else { - *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); - } - - /* - * We should only check the mangled cache - * here if unix_convert failed. This means - * that the path in 'mask' doesn't exist - * on the file system and so we need to look - * for a possible mangle. This patch from - * Tine Smukavec <valentin.smukavec@hermes.si>. - */ - - if (!rc && mangle_is_mangled(mask)) - mangle_check_cache( mask ); - - if (!has_wild) { - pstrcat(directory,"/"); - pstrcat(directory,mask); - error = can_delete(directory,conn,dirtype,bad_path); - if (!NT_STATUS_IS_OK(error)) - return error; - - if (SMB_VFS_UNLINK(conn,directory) == 0) { - count++; - } - } else { - void *dirptr = NULL; - const char *dname; - - if (check_name(directory,conn)) - dirptr = OpenDir(conn, directory, True); - - /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then - the pattern matches against the long name, otherwise the short name - We don't implement this yet XXXX - */ - - if (dirptr) { - error = NT_STATUS_NO_SUCH_FILE; - - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); - - while ((dname = ReadDirName(dirptr))) { - pstring fname; - BOOL sys_direntry = False; - pstrcpy(fname,dname); - - /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if ((dirtype & aDIR)) { - sys_direntry = True; - } else { - continue; - } - } - } - - if(!mask_match(fname, mask, case_sensitive)) - continue; - - if (sys_direntry) { - error = NT_STATUS_OBJECT_NAME_INVALID; - break; - } - - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - error = can_delete(fname,conn,dirtype,bad_path); - if (!NT_STATUS_IS_OK(error)) { - continue; - } - if (SMB_VFS_UNLINK(conn,fname) == 0) - count++; - DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); - } - CloseDir(dirptr); - } - } - - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); - } - - return error; -} - -/**************************************************************************** - Reply to a unlink -****************************************************************************/ - -int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, - int dum_buffsize) -{ - int outsize = 0; - pstring name; - int dirtype; - NTSTATUS status; - START_PROFILE(SMBunlink); - - dirtype = SVAL(inbuf,smb_vwv0); - - srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBunlink); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - - DEBUG(3,("reply_unlink : %s\n",name)); - - 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 - * update after a rename.. - */ - process_pending_change_notify_queue((time_t)0); - - outsize = set_message(outbuf,0,0,True); - - END_PROFILE(SMBunlink); - return outsize; -} - -/**************************************************************************** - Fail for readbraw. -****************************************************************************/ - -void fail_readraw(void) -{ - pstring errstr; - slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)", - strerror(errno) ); - exit_server(errstr); -} - -/**************************************************************************** - Use sendfile in readbraw. -****************************************************************************/ - -void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread, - ssize_t mincount, char *outbuf) -{ - ssize_t ret=0; - -#if defined(WITH_SENDFILE) - /* - * We can only use sendfile on a non-chained packet and on a file - * that is exclusively oplocked. reply_readbraw has already checked the length. - */ - - if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) && - EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) { - DATA_BLOB header; - - _smb_setlen(outbuf,nread); - header.data = outbuf; - header.length = 4; - header.free = NULL; - - if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) { - /* - * Special hack for broken Linux with no 64 bit clean sendfile. If we - * return ENOSYS then pretend we just got a normal read. - */ - if (errno == ENOSYS) - goto normal_read; - - DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); - exit_server("send_file_readbraw sendfile failed"); - } - - } - - normal_read: -#endif - - if (nread > 0) { - ret = read_file(fsp,outbuf+4,startpos,nread); -#if 0 /* mincount appears to be ignored in a W2K server. JRA. */ - if (ret < mincount) - ret = 0; -#else - if (ret < nread) - ret = 0; -#endif - } - - _smb_setlen(outbuf,ret); - if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret) - fail_readraw(); -} - -/**************************************************************************** - Reply to a readbraw (core+ protocol). -****************************************************************************/ - -int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize) -{ - extern struct current_user current_user; - ssize_t maxcount,mincount; - size_t nread = 0; - SMB_OFF_T startpos; - char *header = outbuf; - files_struct *fsp; - START_PROFILE(SMBreadbraw); - - if (srv_is_signing_active()) { - exit_server("reply_readbraw: SMB signing is active - raw reads/writes are disallowed."); - } - - /* - * Special check if an oplock break has been issued - * and the readraw request croses on the wire, we must - * return a zero length response here. - */ - - if(global_oplock_break) { - _smb_setlen(header,0); - if (write_data(smbd_server_fd(),header,4) != 4) - fail_readraw(); - DEBUG(5,("readbraw - oplock break finished\n")); - END_PROFILE(SMBreadbraw); - return -1; - } - - fsp = file_fsp(inbuf,smb_vwv0); - - if (!FNUM_OK(fsp,conn) || !fsp->can_read) { - /* - * fsp could be NULL here so use the value from the packet. JRA. - */ - DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0))); - _smb_setlen(header,0); - if (write_data(smbd_server_fd(),header,4) != 4) - fail_readraw(); - END_PROFILE(SMBreadbraw); - return(-1); - } - - CHECK_FSP(fsp,conn); - - flush_write_cache(fsp, READRAW_FLUSH); - - startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1); - if(CVAL(inbuf,smb_wct) == 10) { - /* - * This is a large offset (64 bit) read. - */ -#ifdef LARGE_SMB_OFF_T - - startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32); - -#else /* !LARGE_SMB_OFF_T */ - - /* - * Ensure we haven't been sent a >32 bit offset. - */ - - if(IVAL(inbuf,smb_vwv8) != 0) { - DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \ -64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) )); - _smb_setlen(header,0); - if (write_data(smbd_server_fd(),header,4) != 4) - fail_readraw(); - END_PROFILE(SMBreadbraw); - return(-1); - } - -#endif /* LARGE_SMB_OFF_T */ - - if(startpos < 0) { - DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos )); - _smb_setlen(header,0); - if (write_data(smbd_server_fd(),header,4) != 4) - fail_readraw(); - END_PROFILE(SMBreadbraw); - return(-1); - } - } - maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF); - mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF); - - /* ensure we don't overrun the packet size */ - maxcount = MIN(65535,maxcount); - - if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { - SMB_OFF_T size = fsp->size; - SMB_OFF_T sizeneeded = startpos + maxcount; - - if (size < sizeneeded) { - SMB_STRUCT_STAT st; - if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) - size = st.st_size; - if (!fsp->can_write) - fsp->size = size; - } - - if (startpos >= size) - nread = 0; - else - nread = MIN(maxcount,(size - startpos)); - } - -#if 0 /* mincount appears to be ignored in a W2K server. JRA. */ - if (nread < mincount) - nread = 0; -#endif - - DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos, - (int)maxcount, (int)mincount, (int)nread ) ); - - send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf); - - DEBUG(5,("readbraw finished\n")); - END_PROFILE(SMBreadbraw); - return -1; -} - -/**************************************************************************** - Reply to a lockread (core+ protocol). -****************************************************************************/ - -int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz) -{ - ssize_t nread = -1; - char *data; - int outsize = 0; - SMB_OFF_T startpos; - size_t numtoread; - NTSTATUS status; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - BOOL my_lock_ctx = False; - START_PROFILE(SMBlockread); - - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); - - release_level_2_oplocks_on_change(fsp); - - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); - - outsize = set_message(outbuf,5,3,True); - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; - - /* - * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+ - * protocol request that predates the read/write lock concept. - * Thus instead of asking for a read lock here we need to ask - * for a write lock. JRA. - * Note that the requested lock size is unaffected by max_recv. - */ - - status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), - (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &my_lock_ctx); - - if (NT_STATUS_V(status)) { -#if 0 - /* - * We used to make lockread a blocking lock. It turns out - * that this isn't on W2k. Found by the Samba 4 RAW-READ torture - * tester. JRA. - */ - - if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos, - (SMB_BIG_UINT)numtoread)) { - END_PROFILE(SMBlockread); - return -1; - } - } -#endif - END_PROFILE(SMBlockread); - return ERROR_NT(status); - } - - /* - * However the requested READ size IS affected by max_recv. Insanity.... JRA. - */ - - if (numtoread > max_recv) { - DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \ -Returning short read of maximum allowed for compatibility with Windows 2000.\n", - (unsigned int)numtoread, (unsigned int)max_recv )); - numtoread = MIN(numtoread,max_recv); - } - nread = read_file(fsp,data,startpos,numtoread); - - if (nread < 0) { - END_PROFILE(SMBlockread); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SSVAL(smb_buf(outbuf),1,nread); - - DEBUG(3,("lockread fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread)); - - END_PROFILE(SMBlockread); - return(outsize); -} - -/**************************************************************************** - Reply to a read. -****************************************************************************/ - -int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - size_t numtoread; - ssize_t nread = 0; - char *data; - SMB_OFF_T startpos; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBread); - - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); - - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); - - outsize = set_message(outbuf,5,3,True); - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - /* - * The requested read size cannot be greater than max_recv. JRA. - */ - if (numtoread > max_recv) { - DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \ -Returning short read of maximum allowed for compatibility with Windows 2000.\n", - (unsigned int)numtoread, (unsigned int)max_recv )); - numtoread = MIN(numtoread,max_recv); - } - - data = smb_buf(outbuf) + 3; - - if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { - END_PROFILE(SMBread); - return ERROR_DOS(ERRDOS,ERRlock); - } - - if (numtoread > 0) - nread = read_file(fsp,data,startpos,numtoread); - - if (nread < 0) { - END_PROFILE(SMBread); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SCVAL(smb_buf(outbuf),0,1); - SSVAL(smb_buf(outbuf),1,nread); - - DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread ) ); - - END_PROFILE(SMBread); - return(outsize); -} - -/**************************************************************************** - Reply to a read and X - possibly using sendfile. -****************************************************************************/ - -int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, - files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt) -{ - ssize_t nread = -1; - char *data = smb_buf(outbuf); - -#if defined(WITH_SENDFILE) - /* - * We can only use sendfile on a non-chained packet and on a file - * that is exclusively oplocked. - */ - - if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && - lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) { - SMB_STRUCT_STAT sbuf; - DATA_BLOB header; - - if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - if (startpos > sbuf.st_size) - goto normal_read; - - if (smb_maxcnt > (sbuf.st_size - startpos)) - smb_maxcnt = (sbuf.st_size - startpos); - - if (smb_maxcnt == 0) - goto normal_read; - - /* - * Set up the packet header before send. We - * assume here the sendfile will work (get the - * correct amount of data). - */ - - SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */ - SSVAL(outbuf,smb_vwv5,smb_maxcnt); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,smb_maxcnt); - SCVAL(outbuf,smb_vwv0,0xFF); - set_message(outbuf,12,smb_maxcnt,False); - header.data = outbuf; - header.length = data - outbuf; - header.free = NULL; - - if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) { - /* - * Special hack for broken Linux with no 64 bit clean sendfile. If we - * return ENOSYS then pretend we just got a normal read. - */ - if (errno == ENOSYS) - goto normal_read; - - DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n", - fsp->fsp_name, strerror(errno) )); - exit_server("send_file_readX sendfile failed"); - } - - DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); - return -1; - } - - normal_read: - -#endif - - nread = read_file(fsp,data,startpos,smb_maxcnt); - - if (nread < 0) { - END_PROFILE(SMBreadX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */ - SSVAL(outbuf,smb_vwv5,nread); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,nread); - - DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_maxcnt, (int)nread ) ); - - return nread; -} - -/**************************************************************************** - Reply to a read and X. -****************************************************************************/ - -int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3); - ssize_t nread = -1; - size_t smb_maxcnt = SVAL(inbuf,smb_vwv5); -#if 0 - size_t smb_mincnt = SVAL(inbuf,smb_vwv6); -#endif - - START_PROFILE(SMBreadX); - - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - END_PROFILE(SMBreadX); - return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize); - } - - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); - - set_message(outbuf,12,0,True); - - if(CVAL(inbuf,smb_wct) == 12) { -#ifdef LARGE_SMB_OFF_T - /* - * This is a large offset (64 bit) read. - */ - startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32); - -#else /* !LARGE_SMB_OFF_T */ - - /* - * Ensure we haven't been sent a >32 bit offset. - */ - - if(IVAL(inbuf,smb_vwv10) != 0) { - 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_DOS(ERRDOS,ERRbadaccess); - } - -#endif /* LARGE_SMB_OFF_T */ - - } - - if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { - END_PROFILE(SMBreadX); - return ERROR_DOS(ERRDOS,ERRlock); - } - - nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt); - if (nread != -1) - nread = chain_reply(inbuf,outbuf,length,bufsize); - - END_PROFILE(SMBreadX); - return nread; -} - -/**************************************************************************** - Reply to a writebraw (core+ or LANMAN1.0 protocol). -****************************************************************************/ - -int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - ssize_t nwritten=0; - ssize_t total_written=0; - size_t numtowrite=0; - size_t tcount; - SMB_OFF_T startpos; - char *data=NULL; - BOOL write_through; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - int outsize = 0; - START_PROFILE(SMBwritebraw); - - if (srv_is_signing_active()) { - exit_server("reply_writebraw: SMB signing is active - raw reads/writes are disallowed."); - } - - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); - - tcount = IVAL(inbuf,smb_vwv1); - startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3); - write_through = BITSETW(inbuf+smb_vwv7,0); - - /* We have to deal with slightly different formats depending - on whether we are using the core+ or lanman1.0 protocol */ - - if(Protocol <= PROTOCOL_COREPLUS) { - numtowrite = SVAL(smb_buf(inbuf),-2); - data = smb_buf(inbuf); - } else { - numtowrite = SVAL(inbuf,smb_vwv10); - data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11); - } - - /* force the error type */ - 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_DOS(ERRDOS,ERRlock)); - } - - if (numtowrite>0) - nwritten = write_file(fsp,data,startpos,numtowrite); - - DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n", - fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through)); - - if (nwritten < (ssize_t)numtowrite) { - END_PROFILE(SMBwritebraw); - return(UNIXERROR(ERRHRD,ERRdiskfull)); - } - - total_written = nwritten; - - /* Return a message to the redirector to tell it to send more bytes */ - 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."); - - /* Now read the raw data into the buffer and write it */ - if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) { - exit_server("secondary writebraw failed"); - } - - /* Even though this is not an smb message, smb_len returns the generic length of an smb message */ - numtowrite = smb_len(inbuf); - - /* Set up outbuf to return the correct return */ - outsize = set_message(outbuf,1,0,True); - SCVAL(outbuf,smb_com,SMBwritec); - SSVAL(outbuf,smb_vwv0,total_written); - - if (numtowrite != 0) { - - if (numtowrite > BUFFER_SIZE) { - DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n", - (unsigned int)numtowrite )); - exit_server("secondary writebraw failed"); - } - - if (tcount > nwritten+numtowrite) { - DEBUG(3,("Client overestimated the write %d %d %d\n", - (int)tcount,(int)nwritten,(int)numtowrite)); - } - - if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) { - DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n", - strerror(errno) )); - exit_server("secondary writebraw failed"); - } - - nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite); - - if (nwritten < (ssize_t)numtowrite) { - SCVAL(outbuf,smb_rcls,ERRHRD); - SSVAL(outbuf,smb_err,ERRdiskfull); - } - - if (nwritten > 0) - total_written += nwritten; - } - - if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn))) - sync_file(conn,fsp); - - DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n", - fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written)); - - /* we won't return a status if write through is not selected - this follows what WfWg does */ - END_PROFILE(SMBwritebraw); - if (!write_through && total_written==tcount) { - -#if RABBIT_PELLET_FIX - /* - * Fix for "rabbit pellet" mode, trigger an early TCP ack by - * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA. - */ - if (!send_keepalive(smbd_server_fd())) - exit_server("reply_writebraw: send of keepalive failed"); -#endif - return(-1); - } - - return(outsize); -} - -/**************************************************************************** - Reply to a writeunlock (core+). -****************************************************************************/ - -int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, - int size, int dum_buffsize) -{ - ssize_t nwritten = -1; - size_t numtowrite; - SMB_OFF_T startpos; - char *data; - NTSTATUS status = NT_STATUS_OK; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - int outsize = 0; - START_PROFILE(SMBwriteunlock); - - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); - - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); - data = smb_buf(inbuf) + 3; - - if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, - WRITE_LOCK,False)) { - END_PROFILE(SMBwriteunlock); - return ERROR_DOS(ERRDOS,ERRlock); - } - - /* The special X/Open SMB protocol handling of - zero length writes is *NOT* done for - this call */ - if(numtowrite == 0) - nwritten = 0; - else - nwritten = write_file(fsp,data,startpos,numtowrite); - - if (lp_syncalways(SNUM(conn))) - sync_file(conn,fsp); - - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - END_PROFILE(SMBwriteunlock); - return(UNIXERROR(ERRHRD,ERRdiskfull)); - } - - if (numtowrite) { - 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_NT(status); - } - } - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - - DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten)); - - END_PROFILE(SMBwriteunlock); - return outsize; -} - -/**************************************************************************** - Reply to a write. -****************************************************************************/ - -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); - - /* 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); - - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL_TO_SMB_OFF_T(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_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, 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(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - END_PROFILE(SMBwrite); - return(UNIXERROR(ERRHRD,ERRdiskfull)); - } - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - - 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)); - - END_PROFILE(SMBwrite); - return(outsize); -} - -/**************************************************************************** - Reply to a write and X. -****************************************************************************/ - -int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3); - size_t numtowrite = SVAL(inbuf,smb_vwv10); - BOOL write_through = BITSETW(inbuf+smb_vwv7,0); - ssize_t nwritten = -1; - unsigned int smb_doff = SVAL(inbuf,smb_vwv11); - unsigned int smblen = smb_len(inbuf); - char *data; - BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF)); - START_PROFILE(SMBwriteX); - - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - END_PROFILE(SMBwriteX); - return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize); - } - - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); - - /* Deal with possible LARGE_WRITEX */ - if (large_writeX) - numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16); - - if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) { - END_PROFILE(SMBwriteX); - return ERROR_DOS(ERRDOS,ERRbadmem); - } - - data = smb_base(inbuf) + smb_doff; - - if(CVAL(inbuf,smb_wct) == 14) { -#ifdef LARGE_SMB_OFF_T - /* - * This is a large offset (64 bit) write. - */ - startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32); - -#else /* !LARGE_SMB_OFF_T */ - - /* - * Ensure we haven't been sent a >32 bit offset. - */ - - if(IVAL(inbuf,smb_vwv12) != 0) { - 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_DOS(ERRDOS,ERRbadaccess); - } - -#endif /* LARGE_SMB_OFF_T */ - } - - if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { - END_PROFILE(SMBwriteX); - return ERROR_DOS(ERRDOS,ERRlock); - } - - /* X/Open SMB protocol says that, unlike SMBwrite - if the length is zero then NO truncation is - done, just a write of zero. To truncate a file, - use SMBwrite. */ - - if(numtowrite == 0) - nwritten = 0; - else - nwritten = write_file(fsp,data,startpos,numtowrite); - - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - END_PROFILE(SMBwriteX); - return(UNIXERROR(ERRHRD,ERRdiskfull)); - } - - set_message(outbuf,6,0,True); - - SSVAL(outbuf,smb_vwv2,nwritten); - if (large_writeX) - SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1); - - if (nwritten < (ssize_t)numtowrite) { - SCVAL(outbuf,smb_rcls,ERRHRD); - SSVAL(outbuf,smb_err,ERRdiskfull); - } - - DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n", - fsp->fnum, (int)numtowrite, (int)nwritten)); - - if (lp_syncalways(SNUM(conn)) || write_through) - sync_file(conn,fsp); - - END_PROFILE(SMBwriteX); - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - Reply to a lseek. -****************************************************************************/ - -int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - SMB_OFF_T startpos; - SMB_OFF_T res= -1; - int mode,umode; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBlseek); - - CHECK_FSP(fsp,conn); - - flush_write_cache(fsp, SEEK_FLUSH); - - mode = SVAL(inbuf,smb_vwv1) & 3; - /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */ - startpos = (SMB_OFF_T)IVALS(inbuf,smb_vwv2); - - switch (mode) { - case 0: - umode = SEEK_SET; - res = startpos; - break; - case 1: - umode = SEEK_CUR; - res = fsp->pos + startpos; - break; - case 2: - umode = SEEK_END; - break; - default: - umode = SEEK_SET; - res = startpos; - break; - } - - if (umode == SEEK_END) { - if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) { - if(errno == EINVAL) { - SMB_OFF_T current_pos = startpos; - SMB_STRUCT_STAT sbuf; - - if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) { - END_PROFILE(SMBlseek); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - current_pos += sbuf.st_size; - if(current_pos < 0) - res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); - } - } - - if(res == -1) { - END_PROFILE(SMBlseek); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - } - - fsp->pos = res; - - outsize = set_message(outbuf,2,0,True); - SIVAL(outbuf,smb_vwv0,res); - - DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n", - fsp->fnum, (double)startpos, (double)res, mode)); - - END_PROFILE(SMBlseek); - return(outsize); -} - -/**************************************************************************** - Reply to a flush. -****************************************************************************/ - -int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - int outsize = set_message(outbuf,0,0,True); - uint16 fnum = SVAL(inbuf,smb_vwv0); - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBflush); - - if (fnum != 0xFFFF) - CHECK_FSP(fsp,conn); - - if (!fsp) { - file_sync_all(conn); - } else { - sync_file(conn,fsp); - } - - DEBUG(3,("flush\n")); - END_PROFILE(SMBflush); - return(outsize); -} - -/**************************************************************************** - Reply to a exit. -****************************************************************************/ - -int reply_exit(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize; - START_PROFILE(SMBexit); - - file_close_pid(SVAL(inbuf,smb_pid)); - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("exit\n")); - - END_PROFILE(SMBexit); - return(outsize); -} - -/**************************************************************************** - Reply to a close - has to deal with closing a directory opened by NT SMB's. -****************************************************************************/ - -int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, - int dum_buffsize) -{ - extern struct current_user current_user; - int outsize = 0; - time_t mtime; - int32 eclass = 0, err = 0; - files_struct *fsp = NULL; - START_PROFILE(SMBclose); - - outsize = set_message(outbuf,0,0,True); - - /* If it's an IPC, pass off to the pipe handler. */ - if (IS_IPC(conn)) { - END_PROFILE(SMBclose); - return reply_pipe_close(conn, inbuf,outbuf); - } - - fsp = file_fsp(inbuf,smb_vwv0); - - /* - * We can only use CHECK_FSP if we know it's not a directory. - */ - - if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) { - END_PROFILE(SMBclose); - return ERROR_DOS(ERRDOS,ERRbadfid); - } - - if(fsp->is_directory) { - /* - * Special case - close NT SMB directory handle. - */ - DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum)); - close_file(fsp,True); - } else { - /* - * Close ordinary file. - */ - int close_err; - pstring file_name; - - /* 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, - conn->num_files_open)); - - /* - * close_file() returns the unix errno if an error - * was detected on close - normally this is due to - * a disk full error. If not then it was probably an I/O error. - */ - - if((close_err = close_file(fsp,True)) != 0) { - errno = close_err; - 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); - - } - - /* We have a cached error */ - if(eclass || err) { - END_PROFILE(SMBclose); - return ERROR_DOS(eclass,err); - } - - END_PROFILE(SMBclose); - return(outsize); -} - -/**************************************************************************** - Reply to a writeclose (Core+ protocol). -****************************************************************************/ - -int reply_writeclose(connection_struct *conn, - char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - size_t numtowrite; - ssize_t nwritten = -1; - int outsize = 0; - int close_err = 0; - SMB_OFF_T startpos; - char *data; - time_t mtime; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBwriteclose); - - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); - - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); - mtime = make_unix_date3(inbuf+smb_vwv4); - data = smb_buf(inbuf) + 1; - - if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) { - END_PROFILE(SMBwriteclose); - return ERROR_DOS(ERRDOS,ERRlock); - } - - nwritten = write_file(fsp,data,startpos,numtowrite); - - set_filetime(conn, fsp->fsp_name,mtime); - - /* - * More insanity. W2K only closes the file if writelen > 0. - * JRA. - */ - - if (numtowrite) { - DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n", - fsp->fsp_name )); - close_err = close_file(fsp,True); - } - - DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n", - fsp->fnum, (int)numtowrite, (int)nwritten, - conn->num_files_open)); - - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - END_PROFILE(SMBwriteclose); - return(UNIXERROR(ERRHRD,ERRdiskfull)); - } - - if(close_err != 0) { - errno = close_err; - END_PROFILE(SMBwriteclose); - return(UNIXERROR(ERRHRD,ERRgeneral)); - } - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - END_PROFILE(SMBwriteclose); - return(outsize); -} - -/**************************************************************************** - Reply to a lock. -****************************************************************************/ - -int reply_lock(connection_struct *conn, - char *inbuf,char *outbuf, int length, int dum_buffsize) -{ - int outsize = set_message(outbuf,0,0,True); - SMB_BIG_UINT count,offset; - NTSTATUS status; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - BOOL my_lock_ctx = False; - - START_PROFILE(SMBlock); - - CHECK_FSP(fsp,conn); - - release_level_2_oplocks_on_change(fsp); - - count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1); - offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3); - - DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fd, fsp->fnum, (double)offset, (double)count)); - - status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx); - if (NT_STATUS_V(status)) { -#if 0 - /* Tests using Samba4 against W2K show this call never creates a blocking lock. */ - if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) { - END_PROFILE(SMBlock); - return -1; - } - } -#endif - END_PROFILE(SMBlock); - return ERROR_NT(status); - } - - END_PROFILE(SMBlock); - return(outsize); -} - -/**************************************************************************** - Reply to a unlock. -****************************************************************************/ - -int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, - int dum_buffsize) -{ - int outsize = set_message(outbuf,0,0,True); - SMB_BIG_UINT count,offset; - NTSTATUS status; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBunlock); - - CHECK_FSP(fsp,conn); - - count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1); - offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3); - - status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset); - if (NT_STATUS_V(status)) { - END_PROFILE(SMBunlock); - return ERROR_NT(status); - } - - DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fd, fsp->fnum, (double)offset, (double)count ) ); - - END_PROFILE(SMBunlock); - return(outsize); -} - -/**************************************************************************** - Reply to a tdis. -****************************************************************************/ - -int reply_tdis(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = set_message(outbuf,0,0,True); - uint16 vuid; - START_PROFILE(SMBtdis); - - vuid = SVAL(inbuf,smb_uid); - - if (!conn) { - DEBUG(4,("Invalid connection in tdis\n")); - END_PROFILE(SMBtdis); - return ERROR_DOS(ERRSRV,ERRinvnid); - } - - conn->used = False; - - close_cnum(conn,vuid); - - END_PROFILE(SMBtdis); - return outsize; -} - -/**************************************************************************** - Reply to a echo. -****************************************************************************/ - -int reply_echo(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int smb_reverb = SVAL(inbuf,smb_vwv0); - int seq_num; - unsigned int data_len = smb_buflen(inbuf); - int outsize = set_message(outbuf,1,data_len,True); - START_PROFILE(SMBecho); - - if (data_len > BUFFER_SIZE) { - DEBUG(0,("reply_echo: data_len too large.\n")); - END_PROFILE(SMBecho); - return -1; - } - - /* copy any incoming data back out */ - if (data_len > 0) - memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len); - - if (smb_reverb > 100) { - DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb)); - smb_reverb = 100; - } - - for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) { - SSVAL(outbuf,smb_vwv0,seq_num); - - smb_setlen(outbuf,outsize - 4); - - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_echo: send_smb failed."); - } - - DEBUG(3,("echo %d times\n", smb_reverb)); - - smb_echo_count++; - - END_PROFILE(SMBecho); - return -1; -} - -/**************************************************************************** - Reply to a printopen. -****************************************************************************/ - -int reply_printopen(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - files_struct *fsp; - START_PROFILE(SMBsplopen); - - if (!CAN_PRINT(conn)) { - END_PROFILE(SMBsplopen); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* Open for exclusive use, write only. */ - fsp = print_fsp_open(conn, NULL); - - if (!fsp) { - END_PROFILE(SMBsplopen); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,fsp->fnum); - - DEBUG(3,("openprint fd=%d fnum=%d\n", - fsp->fd, fsp->fnum)); - - END_PROFILE(SMBsplopen); - return(outsize); -} - -/**************************************************************************** - Reply to a printclose. -****************************************************************************/ - -int reply_printclose(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = set_message(outbuf,0,0,True); - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - int close_err = 0; - START_PROFILE(SMBsplclose); - - CHECK_FSP(fsp,conn); - - if (!CAN_PRINT(conn)) { - END_PROFILE(SMBsplclose); - return ERROR_NT(NT_STATUS_UNSUCCESSFUL); - } - - DEBUG(3,("printclose fd=%d fnum=%d\n", - fsp->fd,fsp->fnum)); - - close_err = close_file(fsp,True); - - if(close_err != 0) { - errno = close_err; - END_PROFILE(SMBsplclose); - return(UNIXERROR(ERRHRD,ERRgeneral)); - } - - END_PROFILE(SMBsplclose); - return(outsize); -} - -/**************************************************************************** - Reply to a printqueue. -****************************************************************************/ - -int reply_printqueue(connection_struct *conn, - char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = set_message(outbuf,2,3,True); - int max_count = SVAL(inbuf,smb_vwv0); - int start_index = SVAL(inbuf,smb_vwv1); - START_PROFILE(SMBsplretq); - - /* we used to allow the client to get the cnum wrong, but that - is really quite gross and only worked when there was only - one printer - I think we should now only accept it if they - get it right (tridge) */ - if (!CAN_PRINT(conn)) { - END_PROFILE(SMBsplretq); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - SSVAL(outbuf,smb_vwv0,0); - SSVAL(outbuf,smb_vwv1,0); - SCVAL(smb_buf(outbuf),0,1); - SSVAL(smb_buf(outbuf),1,0); - - DEBUG(3,("printqueue start_index=%d max_count=%d\n", - start_index, max_count)); - - { - print_queue_struct *queue = NULL; - print_status_struct status; - char *p = smb_buf(outbuf) + 3; - 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; - - if (first >= count) - num_to_get = 0; - else - num_to_get = MIN(num_to_get,count-first); - - - for (i=first;i<first+num_to_get;i++) { - put_dos_date2(p,0,queue[i].time); - SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3)); - SSVAL(p,5, queue[i].job); - SIVAL(p,7,queue[i].size); - SCVAL(p,11,0); - srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII); - p += 28; - } - - if (count > 0) { - 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)); - SCVAL(smb_buf(outbuf),0,1); - SSVAL(smb_buf(outbuf),1,28*count); - } - - SAFE_FREE(queue); - - DEBUG(3,("%d entries returned in queue\n",count)); - } - - END_PROFILE(SMBsplretq); - return(outsize); -} - -/**************************************************************************** - Reply to a printwrite. -****************************************************************************/ - -int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int numtowrite; - int outsize = set_message(outbuf,0,0,True); - char *data; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - - START_PROFILE(SMBsplwr); - - if (!CAN_PRINT(conn)) { - END_PROFILE(SMBsplwr); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); - - numtowrite = SVAL(smb_buf(inbuf),1); - data = smb_buf(inbuf) + 3; - - if (write_file(fsp,data,-1,numtowrite) != numtowrite) { - END_PROFILE(SMBsplwr); - return(UNIXERROR(ERRHRD,ERRdiskfull)); - } - - DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) ); - - END_PROFILE(SMBsplwr); - return(outsize); -} - -/**************************************************************************** - The guts of the mkdir command, split out so it may be called by the NT SMB - code. -****************************************************************************/ - -NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) -{ - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - int ret= -1; - - unix_convert(directory,conn,0,&bad_path,&sbuf); - - if( strchr_m(directory, ':')) { - return NT_STATUS_NOT_A_DIRECTORY; - } - - if (ms_has_wild(directory)) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - - if (check_name(directory, conn)) - ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory)); - - if (ret == -1) { - if(errno == ENOENT) { - if (bad_path) - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - else - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - return map_nt_error_from_unix(errno); - } - - return NT_STATUS_OK; -} - -/**************************************************************************** - 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); - - srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBmkdir); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(directory, conn, inbuf, outbuf); - - status = mkdir_internal(conn, directory); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBmkdir); - return ERROR_NT(status); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) ); - - END_PROFILE(SMBmkdir); - return(outsize); -} - -/**************************************************************************** - Static function used by reply_rmdir to delete an entire directory - tree recursively. Return False on ok, True on fail. -****************************************************************************/ - -static BOOL recursive_rmdir(connection_struct *conn, char *directory) -{ - const char *dname = NULL; - BOOL ret = False; - void *dirptr = OpenDir(conn, directory, False); - - if(dirptr == NULL) - return True; - - while((dname = ReadDirName(dirptr))) { - pstring fullname; - SMB_STRUCT_STAT st; - - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) - continue; - - /* Construct the full name. */ - if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) { - errno = ENOMEM; - ret = True; - break; - } - - pstrcpy(fullname, directory); - pstrcat(fullname, "/"); - pstrcat(fullname, dname); - - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { - ret = True; - break; - } - - if(st.st_mode & S_IFDIR) { - if(recursive_rmdir(conn, fullname)!=0) { - ret = True; - break; - } - if(SMB_VFS_RMDIR(conn,fullname) != 0) { - ret = True; - break; - } - } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { - ret = True; - break; - } - } - CloseDir(dirptr); - return ret; -} - -/**************************************************************************** - The internals of the rmdir code - called elsewhere. -****************************************************************************/ - -BOOL rmdir_internals(connection_struct *conn, char *directory) -{ - BOOL ok; - - ok = (SMB_VFS_RMDIR(conn,directory) == 0); - if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) { - /* - * Check to see if the only thing in this directory are - * vetoed files/directories. If so then delete them and - * retry. If we fail to delete any of them (and we *don't* - * do a recursive delete) then fail the rmdir. - */ - BOOL all_veto_files = True; - const char *dname; - void *dirptr = OpenDir(conn, directory, False); - - if(dirptr != NULL) { - int dirpos = TellDir(dirptr); - while ((dname = ReadDirName(dirptr))) { - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) - continue; - if(!IS_VETO_PATH(conn, dname)) { - all_veto_files = False; - break; - } - } - - if(all_veto_files) { - SeekDir(dirptr,dirpos); - while ((dname = ReadDirName(dirptr))) { - pstring fullname; - SMB_STRUCT_STAT st; - - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) - continue; - - /* Construct the full name. */ - if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) { - errno = ENOMEM; - break; - } - - pstrcpy(fullname, directory); - pstrcat(fullname, "/"); - pstrcat(fullname, dname); - - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) - break; - if(st.st_mode & S_IFDIR) { - if(lp_recursive_veto_delete(SNUM(conn))) { - if(recursive_rmdir(conn, fullname) != 0) - break; - } - if(SMB_VFS_RMDIR(conn,fullname) != 0) - break; - } else if(SMB_VFS_UNLINK(conn,fullname) != 0) - break; - } - CloseDir(dirptr); - /* Retry the rmdir */ - ok = (SMB_VFS_RMDIR(conn,directory) == 0); - } else { - CloseDir(dirptr); - } - } else { - errno = ENOTEMPTY; - } - } - - if (!ok) - DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno))); - - return ok; -} - -/**************************************************************************** - Reply to a rmdir. -****************************************************************************/ - -int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - pstring directory; - int outsize = 0; - BOOL ok = False; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - NTSTATUS status; - START_PROFILE(SMBrmdir); - - srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBrmdir); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) - - unix_convert(directory,conn, NULL,&bad_path,&sbuf); - - if (check_name(directory,conn)) { - dptr_closepath(directory,SVAL(inbuf,smb_pid)); - ok = rmdir_internals(conn, directory); - } - - if (!ok) { - END_PROFILE(SMBrmdir); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRbadpath); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG( 3, ( "rmdir %s\n", directory ) ); - - END_PROFILE(SMBrmdir); - return(outsize); -} - -/******************************************************************* - Resolve wildcards in a filename rename. - Note that name is in UNIX charset and thus potentially can be more - than fstring buffer (255 bytes) especially in default UTF-8 case. - Therefore, we use pstring inside and all calls should ensure that - name2 is at least pstring-long (they do already) -********************************************************************/ - -static BOOL resolve_wildcards(const char *name1, char *name2) -{ - pstring root1,root2; - pstring ext1,ext2; - char *p,*p2, *pname1, *pname2; - int available_space, actual_space; - - - pname1 = strrchr_m(name1,'/'); - pname2 = strrchr_m(name2,'/'); - - if (!pname1 || !pname2) - return(False); - - pstrcpy(root1,pname1); - pstrcpy(root2,pname2); - p = strrchr_m(root1,'.'); - if (p) { - *p = 0; - pstrcpy(ext1,p+1); - } else { - pstrcpy(ext1,""); - } - p = strrchr_m(root2,'.'); - if (p) { - *p = 0; - pstrcpy(ext2,p+1); - } else { - pstrcpy(ext2,""); - } - - p = root1; - p2 = root2; - while (*p2) { - if (*p2 == '?') { - *p2 = *p; - p2++; - } else if (*p2 == '*') { - pstrcpy(p2, p); - break; - } else { - p2++; - } - if (*p) - p++; - } - - p = ext1; - p2 = ext2; - while (*p2) { - if (*p2 == '?') { - *p2 = *p; - p2++; - } else if (*p2 == '*') { - pstrcpy(p2, p); - break; - } else { - p2++; - } - if (*p) - p++; - } - - available_space = sizeof(pstring) - PTR_DIFF(pname2, name2); - - if (ext2[0]) { - actual_space = snprintf(pname2, available_space - 1, "%s.%s", root2, ext2); - if (actual_space >= available_space - 1) { - DEBUG(1,("resolve_wildcards: can't fit resolved name into specified buffer (overrun by %d bytes)\n", - actual_space - available_space)); - } - } else { - pstrcpy_base(pname2, root2, name2); - } - - return(True); -} - -/**************************************************************************** - Ensure open files have their names updates. -****************************************************************************/ - -static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, char *newname) -{ - files_struct *fsp; - BOOL did_rename = False; - - for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) { - DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n", - fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode, - fsp->fsp_name, newname )); - string_set(&fsp->fsp_name, newname); - did_rename = True; - } - - if (!did_rename) - DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n", - (unsigned int)dev, (double)inode, newname )); -} - -/**************************************************************************** - Rename an open file - given an fsp. -****************************************************************************/ - -NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, BOOL replace_if_exists) -{ - SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; - pstring newname_last_component; - NTSTATUS error = NT_STATUS_OK; - BOOL dest_exists; - BOOL rcdest = True; - - ZERO_STRUCT(sbuf); - rcdest = unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf); - - /* Quick check for "." and ".." */ - if (!bad_path && newname_last_component[0] == '.') { - if (!newname_last_component[1] || (newname_last_component[1] == '.' && !newname_last_component[2])) { - return NT_STATUS_ACCESS_DENIED; - } - } - if (!rcdest && bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Ensure newname contains a '/' */ - if(strrchr_m(newname,'/') == 0) { - pstring tmpstr; - - pstrcpy(tmpstr, "./"); - pstrcat(tmpstr, newname); - pstrcpy(newname, tmpstr); - } - - /* - * Check for special case with case preserving and not - * case sensitive. If the old last component differs from the original - * last component only by case, then we should allow - * the rename (user is trying to change the case of the - * filename). - */ - - if((case_sensitive == False) && (case_preserve == True) && - strequal(newname, fsp->fsp_name)) { - char *p; - pstring newname_modified_last_component; - - /* - * Get the last component of the modified name. - * Note that we guarantee that newname contains a '/' - * character above. - */ - p = strrchr_m(newname,'/'); - pstrcpy(newname_modified_last_component,p+1); - - if(strcsequal(newname_modified_last_component, - newname_last_component) == False) { - /* - * Replace the modified last component with - * the original. - */ - pstrcpy(p+1, newname_last_component); - } - } - - /* - * If the src and dest names are identical - including case, - * don't do the rename, just return success. - */ - - if (strcsequal(fsp->fsp_name, newname)) { - DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n", - newname)); - return NT_STATUS_OK; - } - - dest_exists = vfs_object_exist(conn,newname,NULL); - - if(!replace_if_exists && dest_exists) { - DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n", - fsp->fsp_name,newname)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - error = can_rename(newname,conn,&sbuf); - - if (dest_exists && !NT_STATUS_IS_OK(error)) { - DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), fsp->fsp_name,newname)); - if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION)) - error = NT_STATUS_ACCESS_DENIED; - return error; - } - - if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { - DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n", - fsp->fsp_name,newname)); - rename_open_files(conn, fsp->dev, fsp->inode, 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_fsp: Error %s rename %s -> %s\n", - nt_errstr(error), fsp->fsp_name,newname)); - - return error; -} - -/**************************************************************************** - The guts of the rename command, split out so it may be called by the NT SMB - code. -****************************************************************************/ - -NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, uint16 attrs, BOOL replace_if_exists) -{ - pstring directory; - pstring mask; - pstring last_component_src; - pstring last_component_dest; - char *p; - BOOL has_wild; - BOOL bad_path_src = False; - BOOL bad_path_dest = False; - int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL rc = True; - BOOL rcdest = True; - SMB_STRUCT_STAT sbuf1, sbuf2; - - *directory = *mask = 0; - - ZERO_STRUCT(sbuf1); - ZERO_STRUCT(sbuf2); - - rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1); - if (!rc && bad_path_src) { - if (ms_has_wild(last_component_src)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_src[0] == '.') { - if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - } - - rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2); - - /* Quick check for "." and ".." */ - if (last_component_dest[0] == '.') { - if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - } - - /* - * Split the old name into directory and last component - * strings. Note that unix_convert may have stripped off a - * leading ./ from both name and newname if the rename is - * at the root of the share. We need to make sure either both - * name and newname contain a / character or neither of them do - * as this is checked in resolve_wildcards(). - */ - - p = strrchr_m(name,'/'); - if (!p) { - pstrcpy(directory,"."); - pstrcpy(mask,name); - } else { - *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); - *p = '/'; /* Replace needed for exceptional test below. */ - } - - /* - * We should only check the mangled cache - * here if unix_convert failed. This means - * that the path in 'mask' doesn't exist - * on the file system and so we need to look - * for a possible mangle. This patch from - * Tine Smukavec <valentin.smukavec@hermes.si>. - */ - - if (!rc && mangle_is_mangled(mask)) - mangle_check_cache( mask ); - - has_wild = ms_has_wild(mask); - - if (!has_wild) { - /* - * No wildcards - just process the one file. - */ - BOOL is_short_name = mangle_is_8_3(name, True); - - /* Add a terminating '/' to the directory name. */ - pstrcat(directory,"/"); - pstrcat(directory,mask); - - /* Ensure newname contains a '/' also */ - if(strrchr_m(newname,'/') == 0) { - pstring tmpstr; - - pstrcpy(tmpstr, "./"); - pstrcat(tmpstr, newname); - pstrcpy(newname, tmpstr); - } - - DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \ -directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", - case_sensitive, case_preserve, short_case_preserve, directory, - newname, last_component_dest, is_short_name)); - - /* - * Check for special case with case preserving and not - * case sensitive, if directory and newname are identical, - * and the old last component differs from the original - * last component only by case, then we should allow - * the rename (user is trying to change the case of the - * filename). - */ - if((case_sensitive == False) && - (((case_preserve == True) && - (is_short_name == False)) || - ((short_case_preserve == True) && - (is_short_name == True))) && - strcsequal(directory, newname)) { - pstring modified_last_component; - - /* - * Get the last component of the modified name. - * Note that we guarantee that newname contains a '/' - * character above. - */ - p = strrchr_m(newname,'/'); - pstrcpy(modified_last_component,p+1); - - if(strcsequal(modified_last_component, - last_component_dest) == False) { - /* - * Replace the modified last component with - * the original. - */ - pstrcpy(p+1, last_component_dest); - } - } - - resolve_wildcards(directory,newname); - - /* - * The source object must exist. - */ - - if (!vfs_object_exist(conn, directory, &sbuf1)) { - 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_m(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", - nt_errstr(error), directory,newname)); - - return error; - } - - if (!rcdest && bad_path_dest) { - if (ms_has_wild(last_component_dest)) - return NT_STATUS_OBJECT_NAME_INVALID; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - error = can_rename(directory,conn,&sbuf1); - - if (!NT_STATUS_IS_OK(error)) { - DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); - return error; - } - - /* - * If the src and dest names are identical - including case, - * don't do the rename, just return success. - */ - - if (strcsequal(directory, newname)) { - rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); - 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(SMB_VFS_RENAME(conn,directory, newname) == 0) { - DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", - directory,newname)); - rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, 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", - nt_errstr(error), directory,newname)); - - return error; - } else { - /* - * Wildcards - process each file that matches. - */ - void *dirptr = NULL; - const char *dname; - pstring destname; - - if (check_name(directory,conn)) - dirptr = OpenDir(conn, directory, True); - - if (dirptr) { - error = NT_STATUS_NO_SUCH_FILE; -/* Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */ - - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); - - while ((dname = ReadDirName(dirptr))) { - pstring fname; - BOOL sysdir_entry = False; - - pstrcpy(fname,dname); - - /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if (attrs & aDIR) { - sysdir_entry = True; - } else { - continue; - } - } - } - - if(!mask_match(fname, mask, case_sensitive)) - continue; - - if (sysdir_entry) { - error = NT_STATUS_OBJECT_NAME_INVALID; - break; - } - - error = NT_STATUS_ACCESS_DENIED; - slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); - if (!vfs_object_exist(conn, fname, &sbuf1)) { - error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error))); - continue; - } - error = can_rename(fname,conn,&sbuf1); - if (!NT_STATUS_IS_OK(error)) { - DEBUG(6,("rename %s refused\n", fname)); - continue; - } - pstrcpy(destname,newname); - - if (!resolve_wildcards(fname,destname)) { - DEBUG(6,("resolve_wildcards %s %s failed\n", - fname, destname)); - continue; - } - - if (strcsequal(fname,destname)) { - rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); - DEBUG(3,("rename_internals: identical names in wildcard rename %s - success\n", fname)); - count++; - error = NT_STATUS_OK; - continue; - } - - if (!replace_if_exists && - vfs_file_exist(conn,destname, NULL)) { - DEBUG(6,("file_exist %s\n", destname)); - error = NT_STATUS_OBJECT_NAME_COLLISION; - continue; - } - - if (!SMB_VFS_RENAME(conn,fname,destname)) { - rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); - count++; - error = NT_STATUS_OK; - } - DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); - } - CloseDir(dirptr); - } - - if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) { - if (!rcdest && bad_path_dest) { - if (ms_has_wild(last_component_dest)) - return NT_STATUS_OBJECT_NAME_INVALID; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - } - } - - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); - } - - return error; -} - -/**************************************************************************** - Reply to a mv. -****************************************************************************/ - -int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, - int dum_buffsize) -{ - int outsize = 0; - pstring name; - pstring newname; - char *p; - uint16 attrs = SVAL(inbuf,smb_vwv0); - NTSTATUS status; - - START_PROFILE(SMBmv); - - p = smb_buf(inbuf) + 1; - p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBmv); - return ERROR_NT(status); - } - p++; - p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBmv); - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - - DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - - status = rename_internals(conn, name, newname, attrs, False); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBmv); - 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); - - END_PROFILE(SMBmv); - return(outsize); -} - -/******************************************************************* - Copy a file as part of a reply_copy. -******************************************************************/ - -static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, - int count,BOOL target_is_directory, int *err_ret) -{ - int Access,action; - SMB_STRUCT_STAT src_sbuf, sbuf2; - SMB_OFF_T ret=-1; - files_struct *fsp1,*fsp2; - pstring dest; - uint32 dosattrs; - - *err_ret = 0; - - pstrcpy(dest,dest1); - if (target_is_directory) { - char *p = strrchr_m(src,'/'); - if (p) - p++; - else - p = src; - pstrcat(dest,"/"); - pstrcat(dest,p); - } - - if (!vfs_file_exist(conn,src,&src_sbuf)) - return(False); - - fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0,&Access,&action); - - if (!fsp1) - return(False); - - if (!target_is_directory && count) - ofun = FILE_EXISTS_OPEN; - - dosattrs = dos_mode(conn, src, &src_sbuf); - if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) - ZERO_STRUCTP(&sbuf2); - - fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY), - ofun,dosattrs,0,&Access,&action); - - if (!fsp2) { - close_file(fsp1,False); - return(False); - } - - if ((ofun&3) == 1) { - if(SMB_VFS_LSEEK(fsp2,fsp2->fd,0,SEEK_END) == -1) { - DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) )); - /* - * Stop the copy from occurring. - */ - ret = -1; - src_sbuf.st_size = 0; - } - } - - if (src_sbuf.st_size) - 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. - * Thus we don't look at the error return from the - * close of fsp1. - */ - *err_ret = close_file(fsp2,False); - - return(ret == (SMB_OFF_T)src_sbuf.st_size); -} - -/**************************************************************************** - Reply to a file copy. -****************************************************************************/ - -int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int outsize = 0; - pstring name; - pstring directory; - pstring mask,newname; - char *p; - int count=0; - int error = ERRnoaccess; - int err = 0; - BOOL has_wild; - BOOL exists=False; - int tid2 = SVAL(inbuf,smb_vwv0); - int ofun = SVAL(inbuf,smb_vwv1); - int flags = SVAL(inbuf,smb_vwv2); - BOOL target_is_directory=False; - BOOL bad_path1 = False; - BOOL bad_path2 = False; - BOOL rc = True; - SMB_STRUCT_STAT sbuf1, sbuf2; - NTSTATUS status; - - START_PROFILE(SMBcopy); - - *directory = *mask = 0; - - p = smb_buf(inbuf); - p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBcopy); - return ERROR_NT(status); - } - p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBcopy); - return ERROR_NT(status); - } - - DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); - - if (tid2 != conn->cnum) { - /* can't currently handle inter share copies XXXX */ - DEBUG(3,("Rejecting inter-share copy\n")); - END_PROFILE(SMBcopy); - return ERROR_DOS(ERRSRV,ERRinvdevice); - } - - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - - rc = unix_convert(name,conn,0,&bad_path1,&sbuf1); - unix_convert(newname,conn,0,&bad_path2,&sbuf2); - - target_is_directory = VALID_STAT_OF_DIR(sbuf2); - - if ((flags&1) && target_is_directory) { - END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,ERRbadfile); - } - - if ((flags&2) && !target_is_directory) { - END_PROFILE(SMBcopy); - 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_DOS(ERRSRV,ERRerror); - } - - p = strrchr_m(name,'/'); - if (!p) { - pstrcpy(directory,"./"); - pstrcpy(mask,name); - } else { - *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); - } - - /* - * We should only check the mangled cache - * here if unix_convert failed. This means - * that the path in 'mask' doesn't exist - * on the file system and so we need to look - * for a possible mangle. This patch from - * Tine Smukavec <valentin.smukavec@hermes.si>. - */ - - if (!rc && mangle_is_mangled(mask)) - mangle_check_cache( mask ); - - has_wild = ms_has_wild(mask); - - if (!has_wild) { - pstrcat(directory,"/"); - pstrcat(directory,mask); - if (resolve_wildcards(directory,newname) && - copy_file(directory,newname,conn,ofun, count,target_is_directory,&err)) - count++; - if(!count && err) { - errno = err; - END_PROFILE(SMBcopy); - return(UNIXERROR(ERRHRD,ERRgeneral)); - } - if (!count) { - exists = vfs_file_exist(conn,directory,NULL); - } - } else { - void *dirptr = NULL; - const char *dname; - pstring destname; - - if (check_name(directory,conn)) - dirptr = OpenDir(conn, directory, True); - - if (dirptr) { - error = ERRbadfile; - - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); - - 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); - pstrcpy(destname,newname); - if (resolve_wildcards(fname,destname) && - copy_file(fname,destname,conn,ofun, - count,target_is_directory,&err)) - count++; - DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname)); - } - CloseDir(dirptr); - } - } - - if (count == 0) { - if(err) { - /* Error on close... */ - errno = err; - END_PROFILE(SMBcopy); - return(UNIXERROR(ERRHRD,ERRgeneral)); - } - - if (exists) { - END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,error); - } else { - if((errno == ENOENT) && (bad_path1 || bad_path2)) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - END_PROFILE(SMBcopy); - return(UNIXERROR(ERRDOS,error)); - } - } - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,count); - - END_PROFILE(SMBcopy); - return(outsize); -} - -/**************************************************************************** - Reply to a setdir. -****************************************************************************/ - -int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) -{ - int snum; - int outsize = 0; - BOOL ok = False; - pstring newdir; - NTSTATUS status; - - START_PROFILE(pathworks_setdir); - - snum = SNUM(conn); - if (!CAN_SETDIR(snum)) { - END_PROFILE(pathworks_setdir); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(pathworks_setdir); - return ERROR_NT(status); - } - - if (strlen(newdir) == 0) { - ok = True; - } else { - ok = vfs_directory_exist(conn,newdir,NULL); - if (ok) - string_set(&conn->connectpath,newdir); - } - - if (!ok) { - END_PROFILE(pathworks_setdir); - return ERROR_DOS(ERRDOS,ERRbadpath); - } - - outsize = set_message(outbuf,0,0,True); - SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh)); - - DEBUG(3,("setdir %s\n", newdir)); - - END_PROFILE(pathworks_setdir); - return(outsize); -} - -/**************************************************************************** - Get a lock pid, dealing with large count requests. -****************************************************************************/ - -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)); -} - -/**************************************************************************** - Get a lock count, dealing with large count requests. -****************************************************************************/ - -SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format) -{ - SMB_BIG_UINT count = 0; - - if(!large_file_format) { - count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset)); - } else { - -#if defined(HAVE_LONGLONG) - count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) | - ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset))); -#else /* HAVE_LONGLONG */ - - /* - * NT4.x seems to be broken in that it sends large file (64 bit) - * lockingX calls even if the CAP_LARGE_FILES was *not* - * negotiated. For boxes without large unsigned ints truncate the - * lock count by dropping the top 32 bits. - */ - - if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) { - DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n", - (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)), - (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) )); - SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0); - } - - count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)); -#endif /* HAVE_LONGLONG */ - } - - return count; -} - -#if !defined(HAVE_LONGLONG) -/**************************************************************************** - Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-). -****************************************************************************/ - -static uint32 map_lock_offset(uint32 high, uint32 low) -{ - unsigned int i; - uint32 mask = 0; - uint32 highcopy = high; - - /* - * Try and find out how many significant bits there are in high. - */ - - for(i = 0; highcopy; i++) - highcopy >>= 1; - - /* - * We use 31 bits not 32 here as POSIX - * lock offsets may not be negative. - */ - - mask = (~0) << (31 - i); - - if(low & mask) - return 0; /* Fail. */ - - high <<= (31 - i); - - return (high|low); -} -#endif /* !defined(HAVE_LONGLONG) */ - -/**************************************************************************** - Get a lock offset, dealing with large offset requests. -****************************************************************************/ - -SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err) -{ - SMB_BIG_UINT offset = 0; - - *err = False; - - if(!large_file_format) { - offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset)); - } else { - -#if defined(HAVE_LONGLONG) - offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) | - ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset))); -#else /* HAVE_LONGLONG */ - - /* - * NT4.x seems to be broken in that it sends large file (64 bit) - * lockingX calls even if the CAP_LARGE_FILES was *not* - * negotiated. For boxes without large unsigned ints mangle the - * lock offset by mapping the top 32 bits onto the lower 32. - */ - - if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) { - uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)); - uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)); - uint32 new_low = 0; - - if((new_low = map_lock_offset(high, low)) == 0) { - *err = True; - return (SMB_BIG_UINT)-1; - } - - DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n", - (unsigned int)high, (unsigned int)low, (unsigned int)new_low )); - SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0); - SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low); - } - - offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)); -#endif /* HAVE_LONGLONG */ - } - - return offset; -} - -/**************************************************************************** - Reply to a lockingX request. -****************************************************************************/ - -int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) -{ - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - unsigned char locktype = CVAL(inbuf,smb_vwv3); - unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - SMB_BIG_UINT count = 0, offset = 0; - uint16 lock_pid; - int32 lock_timeout = IVAL(inbuf,smb_vwv4); - int i; - char *data; - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; - BOOL err; - BOOL my_lock_ctx = False; - NTSTATUS status; - - START_PROFILE(SMBlockingX); - - CHECK_FSP(fsp,conn); - - data = smb_buf(inbuf); - - if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) { - /* we don't support these - and CANCEL_LOCK makes w2k - and XP reboot so I don't really want to be - compatible! (tridge) */ - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); - } - - /* Check if this is an oplock break on a file - we have granted an oplock on. - */ - if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) { - /* Client can insist on breaking to none. */ - BOOL break_to_none = (oplocklevel == 0); - - DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n", - (unsigned int)oplocklevel, fsp->fnum )); - - /* - * Make sure we have granted an exclusive or batch oplock on this file. - */ - - 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); - return -1; - } else { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRlock); - } - } - - if (remove_oplock(fsp, break_to_none) == False) { - DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n", - fsp->fsp_name )); - } - - /* if this is a pure oplock break request then don't send a reply */ - 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) - DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n", - (unsigned int)CVAL(inbuf,smb_vwv0) )); - END_PROFILE(SMBlockingX); - return -1; - } - } - - /* - * We do this check *after* we have checked this is not a oplock break - * response message. JRA. - */ - - release_level_2_oplocks_on_change(fsp); - - /* Data now points at the beginning of the list - of smb_unlkrng structs */ - for(i = 0; i < (int)num_ulocks; i++) { - 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); - - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - 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 )); - - status = do_unlock(fsp,conn,lock_pid,count,offset); - if (NT_STATUS_V(status)) { - END_PROFILE(SMBlockingX); - return ERROR_NT(status); - } - } - - /* Setup the timeout in seconds. */ - - lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000); - - /* Now do any requested locks */ - data += ((large_file_format ? 20 : 10)*num_ulocks); - - /* Data now points at the beginning of the list - of smb_lkrng structs */ - - for(i = 0; i < (int)num_locks; i++) { - 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); - - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n", - (double)offset, (double)count, (unsigned int)lock_pid, - fsp->fsp_name, (int)lock_timeout )); - - status = do_lock_spin(fsp,conn,lock_pid, count,offset, - ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx); - if (NT_STATUS_V(status)) { - /* - * Interesting fact found by IFSTEST /t LockOverlappedTest... - * Even if it's our own lock context, we need to wait here as - * there may be an unlock on the way. - * So I removed a "&& !my_lock_ctx" from the following - * if statement. JRA. - */ - if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, lock_timeout, i, lock_pid, offset, count)) { - END_PROFILE(SMBlockingX); - return -1; - } - } - break; - } - } - - /* If any of the above locks failed, then we must unlock - all of the previous locks (X/Open spec). */ - if (i != num_locks && num_locks != 0) { - /* - * 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--; i >= 0; i--) { - 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); - - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - do_unlock(fsp,conn,lock_pid,count,offset); - } - END_PROFILE(SMBlockingX); - return ERROR_NT(status); - } - - set_message(outbuf,2,0,True); - - DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n", - fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) ); - - END_PROFILE(SMBlockingX); - return chain_reply(inbuf,outbuf,length,bufsize); -} - -/**************************************************************************** - 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); - - startpos = IVAL_TO_SMB_OFF_T(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) -{ - struct utimbuf unix_times; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBsetattrE); - - outsize = set_message(outbuf,0,0,True); - - if(!fsp || (fsp->conn != conn)) { - END_PROFILE(SMBgetattrE); - return ERROR_DOS(ERRDOS,ERRbadfid); - } - - /* - * Convert the DOS times into unix times. Ignore create - * time as UNIX can't set this. - */ - - unix_times.actime = make_unix_date2(inbuf+smb_vwv3); - unix_times.modtime = make_unix_date2(inbuf+smb_vwv5); - - /* - * Patch from Ray Frush <frush@engr.colostate.edu> - * Sometimes times are sent as zero - ignore them. - */ - - if ((unix_times.actime == 0) && (unix_times.modtime == 0)) { - /* Ignore request */ - if( DEBUGLVL( 3 ) ) { - dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); - dbgtext( "ignoring zero request - not setting timestamps of 0\n" ); - } - END_PROFILE(SMBsetattrE); - return(outsize); - } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) { - /* set modify time = to access time if modify time was 0 */ - unix_times.modtime = unix_times.actime; - } - - /* Set the date on this file */ - if(file_utime(conn, fsp->fsp_name, &unix_times)) { - END_PROFILE(SMBsetattrE); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", - fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) ); - - END_PROFILE(SMBsetattrE); - return(outsize); -} - - -/* 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_TO_SMB_OFF_T(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_TO_SMB_OFF_T(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 */ - if (wbms) - free((char *)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; - } - - free((char *)wbms); - fsp->wbmpx_ptr = NULL; - } - - if(send_response) { - END_PROFILE(SMBwriteBs); - return(outsize); - } - - END_PROFILE(SMBwriteBs); - return(-1); -} - -/**************************************************************************** - Reply to a SMBgetattrE. -****************************************************************************/ - -int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -{ - SMB_STRUCT_STAT sbuf; - int outsize = 0; - int mode; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBgetattrE); - - outsize = set_message(outbuf,11,0,True); - - if(!fsp || (fsp->conn != conn)) { - END_PROFILE(SMBgetattrE); - return ERROR_DOS(ERRDOS,ERRbadfid); - } - - /* Do an fstat on this file */ - if(fsp_stat(fsp, &sbuf)) { - END_PROFILE(SMBgetattrE); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - mode = dos_mode(conn,fsp->fsp_name,&sbuf); - - /* - * Convert the times into dos times. Set create - * date to be last modify date as UNIX doesn't save - * this. - */ - - put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)))); - put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime); - put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime); - - if (mode & aDIR) { - SIVAL(outbuf,smb_vwv6,0); - SIVAL(outbuf,smb_vwv8,0); - } else { - uint32 allocation_size = get_allocation_size(fsp, &sbuf); - SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size); - SIVAL(outbuf,smb_vwv8,allocation_size); - } - SSVAL(outbuf,smb_vwv10, mode); - - DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum)); - - END_PROFILE(SMBgetattrE); - return(outsize); -} diff --git a/source/smbd/rewrite.c b/source/smbd/rewrite.c new file mode 100644 index 00000000000..5e30db1192f --- /dev/null +++ b/source/smbd/rewrite.c @@ -0,0 +1,82 @@ +#include "includes.h" + +/* + + this is a set of temporary stub functions used during the core smbd rewrite. + This file will need to go away before the rewrite is complete +*/ + +void mangle_reset_cache(void) +{} + +void reset_stat_cache(void) +{} + + +BOOL set_current_service(void *conn, BOOL x) +{ return True; } + +void change_to_root_user(void) +{} + +void load_printers(void) +{} + +void file_init(void) +{} + +BOOL init_oplocks(void) +{ return True; } + +BOOL init_change_notify(void) +{ return True; } + + +BOOL pcap_printername_ok(const char *service, char *foo) +{ return True; } + +void become_root(void) +{} + +void unbecome_root(void) +{} + +BOOL namecache_enable(void) +{ return True; } + +BOOL locking_init(int read_only) +{ return True; } + +BOOL share_info_db_init(void) +{ return True; } + +BOOL init_registry(void) +{ return True; } + +BOOL share_access_check(struct request_context *req, struct tcon_context *conn, int snum, uint32 desired_access) +{ return True; } + +BOOL init_names(void) +{ return True; } + +BOOL uid_to_sid(DOM_SID *sid, uid_t uid) +{ + ZERO_STRUCTP(sid); + return True; +} + +BOOL gid_to_sid(DOM_SID *sid, gid_t gid) +{ + ZERO_STRUCTP(sid); + return True; +} + + +BOOL become_user_permanently(uid_t uid, gid_t gid) +{ return True; } + + +int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) +{ + return 0; +} diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c deleted file mode 100644 index fee71b5ec96..00000000000 --- a/source/smbd/sec_ctx.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - Unix SMB/CIFS implementation. - uid/user handling - Copyright (C) Tim Potter 2000 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern struct current_user current_user; - -struct sec_ctx { - uid_t uid; - uid_t gid; - int ngroups; - gid_t *groups; - NT_USER_TOKEN *token; - PRIVILEGE_SET *privs; -}; - -/* A stack of security contexts. We include the current context as being - the first one, so there is room for another MAX_SEC_CTX_DEPTH more. */ - -static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1]; -static int sec_ctx_stack_ndx; - -/**************************************************************************** - Become the specified uid. -****************************************************************************/ - -static BOOL become_uid(uid_t uid) -{ - /* Check for dodgy uid values */ - - if (uid == (uid_t)-1 || - ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) { - static int done; - - if (!done) { - DEBUG(1,("WARNING: using uid %d is a security risk\n", - (int)uid)); - done = 1; - } - } - - /* Set effective user id */ - - set_effective_uid(uid); - - DO_PROFILE_INC(uid_changes); - return True; -} - -/**************************************************************************** - Become the specified gid. -****************************************************************************/ - -static BOOL become_gid(gid_t gid) -{ - /* Check for dodgy gid values */ - - if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) && - (gid == (gid_t)65535))) { - static int done; - - if (!done) { - DEBUG(1,("WARNING: using gid %d is a security risk\n", - (int)gid)); - done = 1; - } - } - - /* Set effective group id */ - - set_effective_gid(gid); - return True; -} - -/**************************************************************************** - Become the specified uid and gid. -****************************************************************************/ - -static BOOL become_id(uid_t uid, gid_t gid) -{ - return become_gid(gid) && become_uid(uid); -} - -/**************************************************************************** - Drop back to root privileges in order to change to another user. -****************************************************************************/ - -static void gain_root(void) -{ - if (non_root_mode()) { - return; - } - - if (geteuid() != 0) { - set_effective_uid(0); - - if (geteuid() != 0) { - DEBUG(0, - ("Warning: You appear to have a trapdoor " - "uid system\n")); - } - } - - if (getegid() != 0) { - set_effective_gid(0); - - if (getegid() != 0) { - DEBUG(0, - ("Warning: You appear to have a trapdoor " - "gid system\n")); - } - } -} - -/**************************************************************************** - Get the list of current groups. -****************************************************************************/ - -int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups) -{ - int i; - gid_t grp; - int ngroups; - gid_t *groups = NULL; - - (*p_ngroups) = 0; - (*p_groups) = NULL; - - /* this looks a little strange, but is needed to cope with - systems that put the current egid in the group list - returned from getgroups() (tridge) */ - save_re_gid(); - set_effective_gid(gid); - setgid(gid); - - ngroups = sys_getgroups(0,&grp); - if (ngroups <= 0) { - goto fail; - } - - if((groups = (gid_t *)malloc(sizeof(gid_t)*(ngroups+1))) == NULL) { - DEBUG(0,("setup_groups malloc fail !\n")); - goto fail; - } - - if ((ngroups = sys_getgroups(ngroups,groups)) == -1) { - goto fail; - } - - restore_re_gid(); - - (*p_ngroups) = ngroups; - (*p_groups) = groups; - - 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] ) ); - } - DEBUG( 3, ( "\n" ) ); - - return ngroups; - -fail: - SAFE_FREE(groups); - restore_re_gid(); - return -1; -} - -/**************************************************************************** - Initialize the groups a user belongs to. -****************************************************************************/ - -BOOL initialise_groups(char *user, uid_t uid, gid_t gid) -{ - struct sec_ctx *prev_ctx_p; - BOOL result = True; - - if (non_root_mode()) { - return True; - } - - become_root(); - - /* Call initgroups() to get user groups */ - - if (winbind_initgroups(user,gid) == -1) { - DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) )); - if (getuid() == 0) { - if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) { - DEBUG(0,("This is probably a problem with the account %s\n", user)); - } - } - result = False; - goto done; - } - - /* Store groups in previous user's security context. This will - always work as the become_root() call increments the stack - pointer. */ - - prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1]; - - SAFE_FREE(prev_ctx_p->groups); - prev_ctx_p->ngroups = 0; - - get_current_groups(gid, &prev_ctx_p->ngroups, &prev_ctx_p->groups); - - done: - unbecome_root(); - - return result; -} - -/**************************************************************************** - Create a new security context on the stack. It is the same as the old - one. User changes are done using the set_sec_ctx() function. -****************************************************************************/ - -BOOL push_sec_ctx(void) -{ - struct sec_ctx *ctx_p; - - /* Check we don't overflow our stack */ - - if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) { - DEBUG(0, ("Security context stack overflow!\n")); - smb_panic("Security context stack overflow!\n"); - } - - /* Store previous user context */ - - sec_ctx_stack_ndx++; - - ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; - - ctx_p->uid = geteuid(); - ctx_p->gid = getegid(); - - DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n", - (unsigned int)ctx_p->uid, (unsigned int)ctx_p->gid, sec_ctx_stack_ndx )); - - ctx_p->token = dup_nt_token(sec_ctx_stack[sec_ctx_stack_ndx-1].token); - - ctx_p->ngroups = sys_getgroups(0, NULL); - - if (ctx_p->ngroups != 0) { - if (!(ctx_p->groups = malloc(ctx_p->ngroups * sizeof(gid_t)))) { - DEBUG(0, ("Out of memory in push_sec_ctx()\n")); - delete_nt_token(&ctx_p->token); - return False; - } - - sys_getgroups(ctx_p->ngroups, ctx_p->groups); - } else { - ctx_p->groups = NULL; - } - - init_privilege(&ctx_p->privs); - if (! NT_STATUS_IS_OK(dup_priv_set(ctx_p->privs, sec_ctx_stack[sec_ctx_stack_ndx-1].privs))) { - DEBUG(0, ("Out of memory on dup_priv_set() in push_sec_ctx()\n")); - delete_nt_token(&ctx_p->token); - destroy_privilege(&ctx_p->privs); - return False; - } - - return True; -} - -/**************************************************************************** - Set the current security context to a given user. -****************************************************************************/ - -void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token, PRIVILEGE_SET *privs) -{ - struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; - - /* Set the security context */ - - DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", - (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx)); - - debug_nt_user_token(DBGC_CLASS, 5, token); - debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups); - - gain_root(); - -#ifdef HAVE_SETGROUPS - sys_setgroups(ngroups, groups); -#endif - - ctx_p->ngroups = ngroups; - - SAFE_FREE(ctx_p->groups); - if (token && (token == ctx_p->token)) - smb_panic("DUPLICATE_TOKEN"); - - delete_nt_token(&ctx_p->token); - if (ctx_p->privs) - reset_privilege(ctx_p->privs); - else - init_privilege(&ctx_p->privs); - - ctx_p->groups = memdup(groups, sizeof(gid_t) * ngroups); - ctx_p->token = dup_nt_token(token); - dup_priv_set(ctx_p->privs, privs); - - become_id(uid, gid); - - ctx_p->uid = uid; - ctx_p->gid = gid; - - /* Update current_user stuff */ - - current_user.uid = uid; - current_user.gid = gid; - current_user.ngroups = ngroups; - current_user.groups = groups; - current_user.nt_user_token = ctx_p->token; - current_user.privs = ctx_p->privs; -} - -/**************************************************************************** - Become root context. -****************************************************************************/ - -void set_root_sec_ctx(void) -{ - /* May need to worry about supplementary groups at some stage */ - - set_sec_ctx(0, 0, 0, NULL, NULL, NULL); -} - -/**************************************************************************** - Pop a security context from the stack. -****************************************************************************/ - -BOOL pop_sec_ctx(void) -{ - struct sec_ctx *ctx_p; - struct sec_ctx *prev_ctx_p; - - /* Check for stack underflow */ - - if (sec_ctx_stack_ndx == 0) { - DEBUG(0, ("Security context stack underflow!\n")); - smb_panic("Security context stack underflow!\n"); - } - - ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; - - /* Clear previous user info */ - - ctx_p->uid = (uid_t)-1; - ctx_p->gid = (gid_t)-1; - - SAFE_FREE(ctx_p->groups); - ctx_p->ngroups = 0; - - delete_nt_token(&ctx_p->token); - destroy_privilege(&ctx_p->privs); - - /* Pop back previous user */ - - sec_ctx_stack_ndx--; - - gain_root(); - - prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx]; - -#ifdef HAVE_SETGROUPS - sys_setgroups(prev_ctx_p->ngroups, prev_ctx_p->groups); -#endif - - become_id(prev_ctx_p->uid, prev_ctx_p->gid); - - /* Update current_user stuff */ - - current_user.uid = prev_ctx_p->uid; - current_user.gid = prev_ctx_p->gid; - current_user.ngroups = prev_ctx_p->ngroups; - current_user.groups = prev_ctx_p->groups; - current_user.nt_user_token = prev_ctx_p->token; - current_user.privs = prev_ctx_p->privs; - - DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", - (unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx)); - - return True; -} - -/* Initialise the security context system */ - -void init_sec_ctx(void) -{ - int i; - struct sec_ctx *ctx_p; - - /* Initialise security context stack */ - - memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH); - - for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) { - sec_ctx_stack[i].uid = (uid_t)-1; - sec_ctx_stack[i].gid = (gid_t)-1; - } - - /* Initialise first level of stack. It is the current context */ - ctx_p = &sec_ctx_stack[0]; - - ctx_p->uid = geteuid(); - ctx_p->gid = getegid(); - - get_current_groups(ctx_p->gid, &ctx_p->ngroups, &ctx_p->groups); - - ctx_p->token = NULL; /* Maps to guest user. */ - ctx_p->privs = NULL; - - /* Initialise current_user global */ - - current_user.uid = ctx_p->uid; - current_user.gid = ctx_p->gid; - current_user.ngroups = ctx_p->ngroups; - current_user.groups = ctx_p->groups; - - /* The conn and vuid are usually taken care of by other modules. - We initialise them here. */ - - current_user.conn = NULL; - current_user.vuid = UID_FIELD_INVALID; - current_user.nt_user_token = NULL; - current_user.privs = NULL; -} diff --git a/source/smbd/server.c b/source/smbd/server.c index 53d07fd905c..90955ff6cb4 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -3,7 +3,8 @@ Main SMB server routines Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Martin Pool 2002 - Copyright (C) Jelmer Vernooij 2002-2003 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) James J Myers 2003 <myersjj@samba.org> 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 @@ -22,446 +23,111 @@ #include "includes.h" -static int am_parent = 1; -/* the last message the was processed */ -int last_message = -1; - -/* a useful macro to debug the last message processed */ -#define LAST_MESSAGE() smb_fn_name(last_message) - -extern pstring user_socket_options; -extern SIG_ATOMIC_T got_sig_term; -extern SIG_ATOMIC_T reload_after_sighup; - -#ifdef WITH_DFS -extern int dcelogin_atmost_once; -#endif /* WITH_DFS */ - -/* really we should have a top level context structure that has the - client file descriptor as an element. That would require a major rewrite :( - - the following 2 functions are an alternative - they make the file - descriptor private to smbd - */ -static int server_fd = -1; - -int smbd_server_fd(void) -{ - return server_fd; -} - -static void smbd_set_server_fd(int fd) -{ - server_fd = fd; - client_setfd(fd); -} - -/**************************************************************************** - Terminate signal. -****************************************************************************/ - -static void sig_term(void) -{ - got_sig_term = 1; - sys_select_signal(); -} - -/**************************************************************************** - Catch a sighup. -****************************************************************************/ - -static void sig_hup(int sig) -{ - reload_after_sighup = 1; - sys_select_signal(); -} - -/**************************************************************************** - Send a SIGTERM to our process group. -*****************************************************************************/ - -static void killkids(void) -{ - if(am_parent) kill(0,SIGTERM); -} - -/**************************************************************************** - Process a sam sync message - not sure whether to do this here or - somewhere else. -****************************************************************************/ - -static void msg_sam_sync(int UNUSED(msg_type), pid_t UNUSED(pid), - void *UNUSED(buf), size_t UNUSED(len)) +/* + called on a fatal error that should cause this server to terminate +*/ +void exit_server(struct server_context *smb, const char *reason) { - DEBUG(10, ("** sam sync message received, ignoring\n")); + smb->model_ops->terminate_connection(smb, reason); } -/**************************************************************************** - Process a sam sync replicate message - not sure whether to do this here or - somewhere else. -****************************************************************************/ -static void msg_sam_repl(int msg_type, pid_t pid, void *buf, size_t len) +/* + setup a single listener of any type + */ +static void setup_listen(struct event_context *events, + const struct model_ops *model_ops, + void (*accept_handler)(struct event_context *,struct fd_event *,time_t,uint16), + struct in_addr *ifip, unsigned port) { - uint32 low_serial; - - if (len != sizeof(uint32)) - return; - - low_serial = *((uint32 *)buf); - - DEBUG(3, ("received sam replication message, serial = 0x%04x\n", - low_serial)); -} + struct fd_event fde; + fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); + if (fde.fd == -1) { + DEBUG(0,("Failed to open socket on %s:%u - %s\n", + inet_ntoa(*ifip), port, strerror(errno))); + return; + } -/**************************************************************************** - Open the socket communication - inetd. -****************************************************************************/ + /* ready to listen */ + set_socket_options(fde.fd, "SO_KEEPALIVE"); + set_socket_options(fde.fd, lp_socket_options()); + + if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) { + DEBUG(0,("Failed to listen on %s:%d - %s\n", + inet_ntoa(*ifip), port, strerror(errno))); + close(fde.fd); + return; + } -static BOOL open_sockets_inetd(void) -{ - /* Started from inetd. fd 0 is the socket. */ - /* We will abort gracefully when the client or remote system - goes away */ - smbd_set_server_fd(dup(0)); - - /* close our standard file descriptors */ - close_low_fds(False); /* Don't close stderr */ + /* we are only interested in read events on the listen socket */ + fde.flags = EVENT_FD_READ; + fde.private = model_ops; + fde.handler = accept_handler; - set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); - set_socket_options(smbd_server_fd(), user_socket_options); - - return True; -} - -static void msg_exit_server(int msg_type, pid_t src, void *buf, size_t len) -{ - exit_server("Got a SHUTDOWN message"); + event_add_fd(events, &fde); } - -/**************************************************************************** - Have we reached the process limit ? -****************************************************************************/ - -static BOOL allowable_number_of_smbd_processes(void) +/* + add a socket address to the list of events, one event per port +*/ +static void add_socket(struct event_context *events, + const struct model_ops *model_ops, + struct in_addr *ifip) { - int max_processes = lp_max_smbd_processes(); - - if (!max_processes) - return True; - - { - TDB_CONTEXT *tdb = conn_tdb_ctx(); - int32 val; - if (!tdb) { - DEBUG(0,("allowable_number_of_smbd_processes: can't open connection tdb.\n" )); - return False; - } - - val = tdb_fetch_int32(tdb, "INFO/total_smbds"); - if (val == -1 && (tdb_error(tdb) != TDB_ERR_NOEXIST)) { - DEBUG(0,("allowable_number_of_smbd_processes: can't fetch INFO/total_smbds. Error %s\n", - tdb_errorstr(tdb) )); - return False; - } - if (val > max_processes) { - DEBUG(0,("allowable_number_of_smbd_processes: number of processes (%d) is over allowed limit (%d)\n", - val, max_processes )); - return False; - } + char *ptr, *tok; + const char *delim = ", "; + + for (tok=strtok_r(lp_smb_ports(), delim, &ptr); + tok; + tok=strtok_r(NULL, delim, &ptr)) { + unsigned port = atoi(tok); + if (port == 0) continue; + setup_listen(events, model_ops, model_ops->accept_connection, ifip, port); } - return True; } /**************************************************************************** Open the socket communication. ****************************************************************************/ - -static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ports) +static void open_sockets_smbd(struct event_context *events, + const struct model_ops *model_ops) { - int num_interfaces = iface_count(); - int num_sockets = 0; - int fd_listenset[FD_SETSIZE]; - fd_set listen_set; - int s; - int i; - char *ports; - - if (!is_daemon) { - return open_sockets_inetd(); - } - - -#ifdef HAVE_ATEXIT - { - static int atexit_set; - if(atexit_set == 0) { - atexit_set=1; - atexit(killkids); - } - } -#endif - - /* Stop zombies */ - CatchChild(); - - FD_ZERO(&listen_set); - - /* use a reasonable default set of ports - listing on 445 and 139 */ - if (!smb_ports) { - ports = lp_smb_ports(); - if (!ports || !*ports) { - ports = smb_xstrdup(SMB_PORTS); - } else { - ports = smb_xstrdup(ports); - } - } else { - ports = smb_xstrdup(smb_ports); - } - if (lp_interfaces() && lp_bind_interfaces_only()) { + int num_interfaces = iface_count(); + int i; + /* We have been given an interfaces line, and been told to only bind to those interfaces. Create a socket per interface and bind to only these. */ - - /* Now open a listen socket for each of the - interfaces. */ for(i = 0; i < num_interfaces; i++) { struct in_addr *ifip = iface_n_ip(i); - fstring tok; - const char *ptr; - if(ifip == NULL) { + if (ifip == NULL) { DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i)); continue; } - for (ptr=ports; next_token(&ptr, tok, NULL, sizeof(tok)); ) { - unsigned port = atoi(tok); - if (port == 0) continue; - s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); - if(s == -1) - return False; - - /* ready to listen */ - set_socket_options(s,"SO_KEEPALIVE"); - set_socket_options(s,user_socket_options); - - /* Set server socket to non-blocking for the accept. */ - set_blocking(s,False); - - if (listen(s, SMBD_LISTEN_BACKLOG) == -1) { - DEBUG(0,("listen: %s\n",strerror(errno))); - close(s); - return False; - } - FD_SET(s,&listen_set); - - num_sockets++; - if (num_sockets >= FD_SETSIZE) { - DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); - return False; - } - } + add_socket(events, model_ops, ifip); } } else { - /* Just bind to 0.0.0.0 - accept connections - from anywhere. */ - - fstring tok; - const char *ptr; - - num_interfaces = 1; + TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd"); - for (ptr=ports; next_token(&ptr, tok, NULL, sizeof(tok)); ) { - unsigned port = atoi(tok); - if (port == 0) continue; - /* open an incoming socket */ - s = open_socket_in(SOCK_STREAM, port, 0, - interpret_addr(lp_socket_address()),True); - if (s == -1) - return(False); - - /* ready to listen */ - set_socket_options(s,"SO_KEEPALIVE"); - set_socket_options(s,user_socket_options); - - /* Set server socket to non-blocking for the accept. */ - set_blocking(s,False); - - if (listen(s, SMBD_LISTEN_BACKLOG) == -1) { - DEBUG(0,("open_sockets_smbd: listen: %s\n", - strerror(errno))); - close(s); - return False; - } - - fd_listenset[num_sockets] = s; - FD_SET(s,&listen_set); - - num_sockets++; - - if (num_sockets >= FD_SETSIZE) { - DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); - return False; - } + struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address()); + /* Just bind to lp_socket_address() (usually 0.0.0.0) */ + if (!mem_ctx) { + smb_panic("No memory"); } + add_socket(events, model_ops, ifip); + talloc_destroy(mem_ctx); } - - SAFE_FREE(ports); - - /* Listen to messages */ - - message_register(MSG_SMB_SAM_SYNC, msg_sam_sync); - message_register(MSG_SMB_SAM_REPL, msg_sam_repl); - message_register(MSG_SHUTDOWN, msg_exit_server); - - /* now accept incoming connections - forking a new process - for each incoming connection */ - DEBUG(2,("waiting for a connection\n")); - while (1) { - fd_set lfds; - int num; - - /* Free up temporary memory from the main smbd. */ - lp_talloc_free(); - - /* Ensure we respond to PING and DEBUG messages from the main smbd. */ - message_dispatch(); - - memcpy((char *)&lfds, (char *)&listen_set, - sizeof(listen_set)); - - num = sys_select(FD_SETSIZE,&lfds,NULL,NULL,NULL); - - if (num == -1 && errno == EINTR) { - if (got_sig_term) { - exit_server("Caught TERM signal"); - } - - /* check for sighup processing */ - if (reload_after_sighup) { - change_to_root_user(); - DEBUG(1,("Reloading services after SIGHUP\n")); - reload_services(False); - reload_after_sighup = 0; - } - - continue; - } - - /* check if we need to reload services */ - check_reload(time(NULL)); - - /* Find the sockets that are read-ready - - accept on these. */ - for( ; num > 0; num--) { - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - - s = -1; - for(i = 0; i < num_sockets; i++) { - if(FD_ISSET(fd_listenset[i],&lfds)) { - s = fd_listenset[i]; - /* Clear this so we don't look - at it again. */ - FD_CLR(fd_listenset[i],&lfds); - break; - } - } - - smbd_set_server_fd(accept(s,&addr,&in_addrlen)); - - if (smbd_server_fd() == -1 && errno == EINTR) - continue; - - if (smbd_server_fd() == -1) { - DEBUG(0,("open_sockets_smbd: accept: %s\n", - strerror(errno))); - continue; - } - - /* Ensure child is set to blocking mode */ - set_blocking(smbd_server_fd(),True); - - if (smbd_server_fd() != -1 && interactive) - return True; - - if (allowable_number_of_smbd_processes() && smbd_server_fd() != -1 && sys_fork()==0) { - /* Child code ... */ - - /* close the listening socket(s) */ - for(i = 0; i < num_sockets; i++) - close(fd_listenset[i]); - - /* close our standard file - descriptors */ - close_low_fds(False); - am_parent = 0; - - set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); - set_socket_options(smbd_server_fd(),user_socket_options); - - /* this is needed so that we get decent entries - in smbstatus for port 445 connects */ - set_remote_machine_name(get_peer_addr(smbd_server_fd()), False); - - /* Reset global variables in util.c so - that client substitutions will be - done correctly in the process. */ - reset_globals_after_fork(); - - /* tdb needs special fork handling - remove CLEAR_IF_FIRST flags */ - if (tdb_reopen_all() == -1) { - DEBUG(0,("tdb_reopen_all failed.\n")); - smb_panic("tdb_reopen_all failed."); - } - - return True; - } - /* The parent doesn't need this socket */ - close(smbd_server_fd()); - - /* Sun May 6 18:56:14 2001 ackley@cs.unm.edu: - Clear the closed fd info out of server_fd -- - and more importantly, out of client_fd in - util_sock.c, to avoid a possible - getpeername failure if we reopen the logs - and use %I in the filename. - */ - - smbd_set_server_fd(-1); - - /* Force parent to check log size after - * spawning child. Fix from - * klausr@ITAP.Physik.Uni-Stuttgart.De. The - * parent smbd will log to logserver.smb. It - * writes only two messages for each child - * started/finished. But each child writes, - * say, 50 messages also in logserver.smb, - * begining with the debug_count of the - * parent, before the child opens its own log - * file logserver.client. In a worst case - * scenario the size of logserver.smb would be - * checked after about 50*50=2500 messages - * (ca. 100kb). - * */ - force_check_log_size(); - - } /* end for num */ - } /* end while 1 */ - -/* NOTREACHED return True; */ } /**************************************************************************** Reload the services file. **************************************************************************/ - -BOOL reload_services(BOOL test) +BOOL reload_services(struct server_context *smb, BOOL test) { BOOL ret; @@ -480,7 +146,9 @@ BOOL reload_services(BOOL test) if (test && !lp_file_list_changed()) return(True); - lp_killunused(conn_snum_used); + if (smb) { + lp_killunused(smb, conn_snum_used); + } ret = lp_load(dyn_CONFIGFILE, False, False, True); @@ -488,19 +156,12 @@ BOOL reload_services(BOOL test) /* perhaps the config filename is now set */ if (!test) - reload_services(True); + reload_services(smb, True); reopen_logs(); load_interfaces(); - { - if (smbd_server_fd() != -1) { - set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); - set_socket_options(smbd_server_fd(), user_socket_options); - } - } - mangle_reset_cache(); reset_stat_cache(); @@ -510,157 +171,62 @@ BOOL reload_services(BOOL test) return(ret); } - -#if DUMP_CORE -/******************************************************************* -prepare to dump a core file - carefully! -********************************************************************/ -static BOOL dump_core(void) -{ - char *p; - pstring dname; - - pstrcpy(dname,lp_logfile()); - if ((p=strrchr_m(dname,'/'))) *p=0; - pstrcat(dname,"/corefiles"); - mkdir(dname,0700); - sys_chown(dname,getuid(),getgid()); - chmod(dname,0700); - if (chdir(dname)) return(False); - umask(~(0700)); - -#ifdef HAVE_GETRLIMIT -#ifdef RLIMIT_CORE - { - struct rlimit rlp; - getrlimit(RLIMIT_CORE, &rlp); - rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur); - setrlimit(RLIMIT_CORE, &rlp); - getrlimit(RLIMIT_CORE, &rlp); - DEBUG(3,("Core limits now %d %d\n", - (int)rlp.rlim_cur,(int)rlp.rlim_max)); - } -#endif -#endif - - - DEBUG(0,("Dumping core in %s\n", dname)); - abort(); - return(True); -} -#endif - /**************************************************************************** - Exit the server. + Initialise connect, service and file structs. ****************************************************************************/ - -void exit_server(const char *reason) +static BOOL init_structs(void) { - static int firsttime=1; - extern char *last_inbuf; - extern struct auth_context *negprot_global_auth_context; - - if (!firsttime) - exit(0); - firsttime = 0; - - change_to_root_user(); - DEBUG(2,("Closing connections\n")); - - if (negprot_global_auth_context) { - (negprot_global_auth_context->free)(&negprot_global_auth_context); - } - - conn_close_all(); - - invalidate_all_vuids(); - - print_notify_send_messages(3); /* 3 second timeout. */ - - /* run all registered exit events */ - smb_run_exit_events(); - - /* delete our entry in the connections database. */ - yield_connection(NULL,""); - - respond_to_all_remaining_local_messages(); - decrement_smbd_process_count(); - -#ifdef WITH_DFS - if (dcelogin_atmost_once) { - dfs_unlogin(); - } -#endif - - if (!reason) { - int oldlevel = DEBUGLEVEL; - DEBUGLEVEL = 10; - DEBUG(0,("Last message was %s\n",smb_fn_name(last_message))); - if (last_inbuf) - show_msg(last_inbuf); - DEBUGLEVEL = oldlevel; - DEBUG(0,("===============================================================\n")); -#if DUMP_CORE - if (dump_core()) return; -#endif - } + init_names(); + file_init(); + secrets_init(); - locking_end(); - printing_end(); + /* we want to re-seed early to prevent time delays causing + client problems at a later date. (tridge) */ + generate_random_buffer(NULL, 0, False); - DEBUG(3,("Server exit (%s)\n", (reason ? reason : ""))); - exit(0); + return True; } -/**************************************************************************** - Initialise connect, service and file structs. -****************************************************************************/ -static BOOL init_structs(void ) +/* + setup the events for the chosen process model +*/ +static void setup_process_model(struct event_context *events, + const char *model) { - /* - * Set the machine NETBIOS name if not already - * set from the config file. - */ - - if (!init_names()) - return False; + const struct model_ops *ops; - conn_init(); + process_model_init(); - file_init(); + ops = process_model_byname(model); + if (!ops) { + DEBUG(0,("Unknown process model '%s'\n", model)); + exit(-1); + } - /* for RPC pipes */ - init_rpc_pipe_hnd(); + ops->model_startup(); - init_dptrs(); + /* now setup the listening sockets, adding + event handlers to the events structure */ + open_sockets_smbd(events, ops); - secrets_init(); - - return True; + /* setup any sockets we need to listen on for RPC over TCP */ + open_sockets_rpc(events, ops); } /**************************************************************************** main program. ****************************************************************************/ - -/* Declare prototype for build_options() to avoid having to run it through - mkproto.h. Mixing $(builddir) and $(srcdir) source files in the current - prototype generation system is too complicated. */ - -void build_options(BOOL screen); - int main(int argc,const char *argv[]) { - /* shall I run as a daemon */ - static BOOL is_daemon = False; - static BOOL interactive = False; - static BOOL Fork = True; - static BOOL log_stdout = False; - static char *ports = NULL; + BOOL is_daemon = False; + BOOL interactive = False; + BOOL Fork = True; + BOOL log_stdout = False; int opt; poptContext pc; - + struct event_context *events; + const char *model = "standard"; struct poptOption long_options[] = { POPT_AUTOHELP {"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" }, @@ -668,39 +234,32 @@ void build_options(BOOL screen); {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools & etc)" }, {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" }, {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" }, - {"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"}, + {"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports"}, + {"model", 'M', POPT_ARG_STRING, &model, 0, "select process model"}, POPT_COMMON_SAMBA { NULL } }; - -#ifdef HAVE_SET_AUTH_PARAMETERS - set_auth_parameters(argc,argv); -#endif - + pc = poptGetContext("smbd", argc, argv, long_options, 0); while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case 'b': - build_options(True); /* Display output to screen as well as debug */ + /* Display output to screen as well as debug */ + build_options(True); exit(0); break; + case 'p': + lp_set_cmdline("smb ports", poptGetOptArg(pc)); + break; } } - poptFreeContext(pc); -#ifdef HAVE_SETLUID - /* needed for SecureWare on SCO */ - setluid(0); -#endif - - sec_init(); + events = event_context_init(); load_case_tables(); - set_remote_machine_name("smbd", False); - if (interactive) { Fork = False; log_stdout = True; @@ -710,22 +269,9 @@ void build_options(BOOL screen); DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n")); exit(1); } - - setup_logging(argv[0],log_stdout); - - /* we want to re-seed early to prevent time delays causing - client problems at a later date. (tridge) */ - generate_random_buffer(NULL, 0, False); - - /* make absolutely sure we run as root - to handle cases where people - are crazy enough to have it setuid */ - - gain_root_privilege(); - gain_root_group_privilege(); + setup_logging(argv[0], log_stdout?DEBUG_STDOUT:DEBUG_FILE); fault_setup((void (*)(void *))exit_server); - CatchSignal(SIGTERM , SIGNAL_CAST sig_term); - CatchSignal(SIGHUP,SIGNAL_CAST sig_hup); /* we are never interested in SIGPIPE */ BlockSignals(True,SIGPIPE); @@ -750,15 +296,10 @@ void build_options(BOOL screen); so set our umask to 0 */ umask(0); - init_sec_ctx(); - reopen_logs(); - DEBUG(0,( "smbd version %s started.\n", SAMBA_VERSION_STRING)); - DEBUGADD(0,( "Copyright Andrew Tridgell and the Samba Team 1992-2004\n")); - - DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", - (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid())); + DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING)); + DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2004\n")); /* Output the build options to the debug log */ build_options(False); @@ -767,25 +308,13 @@ void build_options(BOOL screen); DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); exit(1); } - - /* - * Do this before reload_services. - */ - - if (!reload_services(False)) + DEBUG(0,("Using %s process model\n", model)); + + if (!reload_services(NULL, False)) return(-1); init_structs(); -#ifdef WITH_PROFILE - if (!profile_setup(False)) { - DEBUG(0,("ERROR: failed to setup profiling\n")); - return -1; - } -#endif - - DEBUG(3,( "loaded services\n")); - if (!is_daemon && !is_a_socket(0)) { if (!interactive) DEBUG(0,("standard input is not a socket, assuming -D option\n")); @@ -799,111 +328,23 @@ void build_options(BOOL screen); } if (is_daemon && !interactive) { - DEBUG( 3, ( "Becoming a daemon.\n" ) ); + DEBUG(3,("Becoming a daemon.\n")); become_daemon(Fork); } -#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)) + if (!directory_exist(lp_lockdir(), NULL)) { mkdir(lp_lockdir(), 0755); - - if (is_daemon) - pidfile_create("smbd"); - - /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */ - if (!message_init()) - exit(1); - - if (!session_init()) - exit(1); - - if (conn_tdb_ctx() == NULL) - exit(1); - - if (!locking_init(0)) - exit(1); - - if (!share_info_db_init()) - exit(1); - - namecache_enable(); - - if (!init_registry()) - exit(1); - - if (!print_backend_init()) - exit(1); - - /* Setup the main smbd so that we can get messages. */ - claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD); - - /* - DO NOT ENABLE THIS TILL YOU COPE WITH KILLING THESE TASKS AND INETD - THIS *killed* LOTS OF BUILD FARM MACHINES. IT CREATED HUNDREDS OF - smbd PROCESSES THAT NEVER DIE - start_background_queue(); - */ - - if (!open_sockets_smbd(is_daemon, interactive, ports)) - exit(1); - - /* - * everything after this point is run after the fork() - */ - - /* Initialise the password backed before the global_sam_sid - to ensure that we fetch from ldap before we make a domain sid up */ - - if(!initialize_password_db(False)) - exit(1); - - if(!get_global_sam_sid()) { - DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); - exit(1); - } - - static_init_rpc; - - init_modules(); - - /* possibly reload the services file. */ - reload_services(True); - - if (!init_account_policy()) { - DEBUG(0,("Could not open account policy tdb.\n")); - exit(1); } - if (*lp_rootdir()) { - if (sys_chroot(lp_rootdir()) == 0) - DEBUG(2,("Changed root to %s\n", lp_rootdir())); + if (is_daemon) { + pidfile_create("smbd"); } - /* Setup oplocks */ - if (!init_oplocks()) - exit(1); - - /* Setup change notify */ - if (!init_change_notify()) - exit(1); - - /* re-initialise the timezone */ - TimeInit(); + register_msg_pool_usage(); + register_dmalloc_msgs(); - /* register our message handlers */ - message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis); + setup_process_model(events, model); - smbd_process(); - - namecache_shutdown(); - exit_server("normal exit"); - return(0); + /* wait for events */ + return event_loop_wait(events); } diff --git a/source/smbd/service.c b/source/smbd/service.c deleted file mode 100644 index 1910ef9b72b..00000000000 --- a/source/smbd/service.c +++ /dev/null @@ -1,838 +0,0 @@ -/* - Unix SMB/CIFS implementation. - service (connection) opening and closing - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern struct timeval smb_last_time; -extern int case_default; -extern BOOL case_preserve; -extern BOOL short_case_preserve; -extern BOOL case_mangle; -extern BOOL case_sensitive; -extern BOOL use_mangled_map; -extern userdom_struct current_user_info; - - -/**************************************************************************** - Load parameters specific to a connection/service. -****************************************************************************/ - -BOOL set_current_service(connection_struct *conn,BOOL do_chdir) -{ - extern char magic_char; - static connection_struct *last_conn; - int snum; - - if (!conn) { - last_conn = NULL; - return(False); - } - - conn->lastused = smb_last_time.tv_sec; - - snum = SNUM(conn); - - if (do_chdir && - vfs_ChDir(conn,conn->connectpath) != 0 && - vfs_ChDir(conn,conn->origpath) != 0) { - DEBUG(0,("chdir (%s) failed\n", - conn->connectpath)); - return(False); - } - - if (conn == last_conn) - return(True); - - last_conn = conn; - - case_default = lp_defaultcase(snum); - case_preserve = lp_preservecase(snum); - short_case_preserve = lp_shortpreservecase(snum); - case_mangle = lp_casemangle(snum); - case_sensitive = lp_casesensitive(snum); - magic_char = lp_magicchar(snum); - use_mangled_map = (*lp_mangled_map(snum) ? True:False); - return(True); -} - -/**************************************************************************** - Add a home service. Returns the new service number or -1 if fail. -****************************************************************************/ - -int add_home_service(const char *service, const char *username, const char *homedir) -{ - int iHomeService; - - if (!service || !homedir) - return -1; - - if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) - return -1; - - /* - * If this is a winbindd provided username, remove - * the domain component before adding the service. - * Log a warning if the "path=" parameter does not - * include any macros. - */ - - { - const char *p = strchr(service,*lp_winbind_separator()); - - /* We only want the 'user' part of the string */ - if (p) { - service = p + 1; - } - } - - if (!lp_add_home(service, iHomeService, username, homedir)) { - return -1; - } - - return lp_servicenumber(service); - -} - - -/** - * Find a service entry. - * - * @param service is modified (to canonical form??) - **/ - -int find_service(fstring service) -{ - int iService; - - all_string_sub(service,"\\","/",0); - - iService = lp_servicenumber(service); - - /* now handle the special case of a home directory */ - if (iService < 0) { - char *phome_dir = get_user_home_dir(service); - - if(!phome_dir) { - /* - * Try mapping the servicename, it may - * be a Windows to unix mapped user name. - */ - if(map_username(service)) - phome_dir = get_user_home_dir(service); - } - - DEBUG(3,("checking for home directory %s gave %s\n",service, - phome_dir?phome_dir:"(NULL)")); - - iService = add_home_service(service,service /* 'username' */, phome_dir); - } - - /* If we still don't have a service, attempt to add it as a printer. */ - if (iService < 0) { - int iPrinterService; - - if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) { - char *pszTemp; - - DEBUG(3,("checking whether %s is a valid printer name...\n", service)); - pszTemp = lp_printcapname(); - if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) { - DEBUG(3,("%s is a valid printer name\n", service)); - DEBUG(3,("adding %s as a printer service\n", service)); - lp_add_printer(service, iPrinterService); - iService = lp_servicenumber(service); - if (iService < 0) { - DEBUG(0,("failed to add %s as a printer service!\n", service)); - } - } else { - DEBUG(3,("%s is not a valid printer name\n", service)); - } - } - } - - /* Check for default vfs service? Unsure whether to implement this */ - if (iService < 0) { - } - - /* just possibly it's a default service? */ - if (iService < 0) { - char *pdefservice = lp_defaultservice(); - if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) { - /* - * We need to do a local copy here as lp_defaultservice() - * returns one of the rotating lp_string buffers that - * could get overwritten by the recursive find_service() call - * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>. - */ - pstring defservice; - pstrcpy(defservice, pdefservice); - iService = find_service(defservice); - if (iService >= 0) { - all_string_sub(service, "_","/",0); - iService = lp_add_service(service, iService); - } - } - } - - if (iService >= 0) { - if (!VALID_SNUM(iService)) { - DEBUG(0,("Invalid snum %d for %s\n",iService, service)); - iService = -1; - } - } - - if (iService < 0) - DEBUG(3,("find_service() failed to find service %s\n", service)); - - return (iService); -} - - -/**************************************************************************** - do some basic sainity checks on the share. - This function modifies dev, ecode. -****************************************************************************/ - -static NTSTATUS share_sanity_checks(int snum, fstring dev) -{ - - if (!lp_snum_ok(snum) || - !check_access(smbd_server_fd(), - lp_hostsallow(snum), lp_hostsdeny(snum))) { - return NT_STATUS_ACCESS_DENIED; - } - - if (dev[0] == '?' || !dev[0]) { - if (lp_print_ok(snum)) { - fstrcpy(dev,"LPT1:"); - } else if (strequal(lp_fstype(snum), "IPC")) { - fstrcpy(dev, "IPC"); - } else { - fstrcpy(dev,"A:"); - } - } - - strupper_m(dev); - - if (lp_print_ok(snum)) { - if (!strequal(dev, "LPT1:")) { - return NT_STATUS_BAD_DEVICE_TYPE; - } - } else if (strequal(lp_fstype(snum), "IPC")) { - if (!strequal(dev, "IPC")) { - return NT_STATUS_BAD_DEVICE_TYPE; - } - } else if (!strequal(dev, "A:")) { - return NT_STATUS_BAD_DEVICE_TYPE; - } - - /* Behave as a printer if we are supposed to */ - if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) { - fstrcpy(dev, "LPT1:"); - } - - return NT_STATUS_OK; -} - -/**************************************************************************** - Make a connection, given the snum to connect to, and the vuser of the - connecting user if appropriate. -****************************************************************************/ - -static connection_struct *make_connection_snum(int snum, user_struct *vuser, - DATA_BLOB password, - const char *pdev, NTSTATUS *status) -{ - struct passwd *pass = NULL; - BOOL guest = False; - connection_struct *conn; - struct stat st; - fstring user; - fstring dev; - - *user = 0; - fstrcpy(dev, pdev); - - if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) { - return NULL; - } - - conn = conn_new(); - if (!conn) { - DEBUG(0,("Couldn't find free connection.\n")); - *status = NT_STATUS_INSUFFICIENT_RESOURCES; - return NULL; - } - - if (lp_guest_only(snum)) { - const char *guestname = lp_guestaccount(); - guest = True; - pass = getpwnam_alloc(guestname); - if (!pass) { - DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname)); - conn_free(conn); - *status = NT_STATUS_NO_SUCH_USER; - return NULL; - } - fstrcpy(user,pass->pw_name); - conn->force_user = True; - conn->uid = pass->pw_uid; - conn->gid = pass->pw_gid; - string_set(&conn->user,pass->pw_name); - passwd_free(&pass); - DEBUG(3,("Guest only user %s\n",user)); - } else if (vuser) { - if (vuser->guest) { - if (!lp_guest_ok(snum)) { - DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } else { - if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) { - DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } - conn->vuid = vuser->vuid; - conn->uid = vuser->uid; - conn->gid = vuser->gid; - string_set(&conn->user,vuser->user.unix_name); - fstrcpy(user,vuser->user.unix_name); - guest = vuser->guest; - } else if (lp_security() == SEC_SHARE) { - /* add it as a possible user name if we - are in share mode security */ - add_session_user(lp_servicename(snum)); - /* shall we let them in? */ - if (!authorise_login(snum,user,password,&guest)) { - DEBUG( 2, ( "Invalid username/password for [%s]\n", - lp_servicename(snum)) ); - conn_free(conn); - *status = NT_STATUS_WRONG_PASSWORD; - return NULL; - } - pass = Get_Pwnam(user); - conn->force_user = True; - conn->uid = pass->pw_uid; - conn->gid = pass->pw_gid; - string_set(&conn->user, pass->pw_name); - fstrcpy(user, pass->pw_name); - - } else { - DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - - add_session_user(user); - - safe_strcpy(conn->client_address, client_addr(), - sizeof(conn->client_address)-1); - conn->num_files_open = 0; - conn->lastused = time(NULL); - conn->service = snum; - conn->used = True; - conn->printer = (strncmp(dev,"LPT",3) == 0); - conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$")); - conn->dirptr = NULL; - conn->veto_list = NULL; - conn->hide_list = NULL; - conn->veto_oplock_list = NULL; - string_set(&conn->dirpath,""); - string_set(&conn->user,user); - conn->nt_user_token = NULL; - conn->privs = NULL; - - conn->read_only = lp_readonly(conn->service); - conn->admin_user = False; - - /* - * If force user is true, then store the - * given userid and also the groups - * of the user we're forcing. - */ - - if (*lp_force_user(snum)) { - struct passwd *pass2; - pstring fuser; - pstrcpy(fuser,lp_force_user(snum)); - - /* Allow %S to be used by force user. */ - pstring_sub(fuser,"%S",lp_servicename(snum)); - - pass2 = (struct passwd *)Get_Pwnam(fuser); - if (pass2) { - conn->uid = pass2->pw_uid; - conn->gid = pass2->pw_gid; - string_set(&conn->user,pass2->pw_name); - fstrcpy(user,pass2->pw_name); - conn->force_user = True; - DEBUG(3,("Forced user %s\n",user)); - } else { - DEBUG(1,("Couldn't find user %s\n",fuser)); - conn_free(conn); - *status = NT_STATUS_NO_SUCH_USER; - return NULL; - } - } - -#ifdef HAVE_GETGRNAM - /* - * If force group is true, then override - * any groupid stored for the connecting user. - */ - - if (*lp_force_group(snum)) { - gid_t gid; - pstring gname; - pstring tmp_gname; - BOOL user_must_be_member = False; - - pstrcpy(tmp_gname,lp_force_group(snum)); - - if (tmp_gname[0] == '+') { - user_must_be_member = True; - /* even now, tmp_gname is null terminated */ - pstrcpy(gname,&tmp_gname[1]); - } else { - pstrcpy(gname,tmp_gname); - } - /* default service may be a group name */ - pstring_sub(gname,"%S",lp_servicename(snum)); - gid = nametogid(gname); - - if (gid != (gid_t)-1) { - - /* - * If the user has been forced and the forced group starts - * with a '+', then we only set the group to be the forced - * group if the forced user is a member of that group. - * Otherwise, the meaning of the '+' would be ignored. - */ - if (conn->force_user && user_must_be_member) { - if (user_in_group_list( user, gname, NULL, 0)) { - conn->gid = gid; - DEBUG(3,("Forced group %s for member %s\n",gname,user)); - } - } else { - conn->gid = gid; - DEBUG(3,("Forced group %s\n",gname)); - } - conn->force_group = True; - } else { - DEBUG(1,("Couldn't find group %s\n",gname)); - conn_free(conn); - *status = NT_STATUS_NO_SUCH_GROUP; - return NULL; - } - } -#endif /* HAVE_GETGRNAM */ - - { - pstring s; - pstrcpy(s,lp_pathname(snum)); - standard_sub_conn(conn,s,sizeof(s)); - string_set(&conn->connectpath,s); - DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum))); - } - - if (conn->force_user || conn->force_group) { - - /* groups stuff added by ih */ - conn->ngroups = 0; - conn->groups = NULL; - - /* Find all the groups this uid is in and - store them. Used by change_to_user() */ - initialise_groups(conn->user, conn->uid, conn->gid); - get_current_groups(conn->gid, &conn->ngroups,&conn->groups); - - conn->nt_user_token = create_nt_token(conn->uid, conn->gid, - conn->ngroups, conn->groups, - guest); - - init_privilege(&(conn->privs)); - pdb_get_privilege_set(conn->nt_user_token->user_sids, conn->nt_user_token->num_sids, conn->privs); - } - - /* - * New code to check if there's a share security descripter - * added from NT server manager. This is done after the - * smb.conf checks are done as we need a uid and token. JRA. - * - */ - - { - BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA); - - if (!can_write) { - if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) { - /* No access, read or write. */ - DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n", - lp_servicename(snum))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } else { - conn->read_only = True; - } - } - } - /* Initialise VFS function pointers */ - - if (!smbd_vfs_init(conn)) { - DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn)))); - conn_free(conn); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } - -/* ROOT Activities: */ - /* check number of connections */ - if (!claim_connection(conn, - lp_servicename(SNUM(conn)), - lp_max_connections(SNUM(conn)), - False,0)) { - DEBUG(1,("too many connections - rejected\n")); - conn_free(conn); - *status = NT_STATUS_INSUFFICIENT_RESOURCES; - return NULL; - } - - /* Preexecs are done here as they might make the dir we are to ChDir to below */ - /* execute any "root preexec = " line */ - if (*lp_rootpreexec(SNUM(conn))) { - int ret; - pstring cmd; - pstrcpy(cmd,lp_rootpreexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); - DEBUG(5,("cmd=%s\n",cmd)); - ret = smbrun(cmd,NULL); - if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) { - DEBUG(1,("root preexec gave %d - failing connection\n", ret)); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } - -/* USER Activites: */ - if (!change_to_user(conn, conn->vuid)) { - /* No point continuing if they fail the basic checks */ - DEBUG(0,("Can't become connected user!\n")); - conn_free(conn); - *status = NT_STATUS_LOGON_FAILURE; - return NULL; - } - - /* Remember that a different vuid can connect later without these checks... */ - - /* Preexecs are done here as they might make the dir we are to ChDir to below */ - /* execute any "preexec = " line */ - if (*lp_preexec(SNUM(conn))) { - int ret; - pstring cmd; - pstrcpy(cmd,lp_preexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); - ret = smbrun(cmd,NULL); - if (ret != 0 && lp_preexec_close(SNUM(conn))) { - DEBUG(1,("preexec gave %d - failing connection\n", ret)); - change_to_root_user(); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } - -#ifdef WITH_FAKE_KASERVER - if (lp_afs_share(SNUM(conn))) { - afs_login(conn); - } -#endif - -#if CHECK_PATH_ON_TCONX - /* win2000 does not check the permissions on the directory - during the tree connect, instead relying on permission - check during individual operations. To match this behaviour - I have disabled this chdir check (tridge) */ - if (vfs_ChDir(conn,conn->connectpath) != 0) { - DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n", - get_remote_machine_name(), conn->client_address, - conn->connectpath,strerror(errno))); - change_to_root_user(); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } -#else - /* the alternative is just to check the directory exists */ - if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { - DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn)))); - change_to_root_user(); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } -#endif - - string_set(&conn->origpath,conn->connectpath); - -#if SOFTLINK_OPTIMISATION - /* resolve any soft links early if possible */ - if (vfs_ChDir(conn,conn->connectpath) == 0) { - pstring s; - pstrcpy(s,conn->connectpath); - vfs_GetWd(conn,s); - string_set(&conn->connectpath,s); - vfs_ChDir(conn,conn->connectpath); - } -#endif - - /* - * Print out the 'connected as' stuff here as we need - * to know the effective uid and gid we will be using - * (at least initially). - */ - - if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { - dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address ); - dbgtext( "%s", srv_is_signing_active() ? "signed " : ""); - dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) ); - dbgtext( "initially as user %s ", user ); - dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); - dbgtext( "(pid %d)\n", (int)sys_getpid() ); - } - - /* Add veto/hide lists */ - if (!IS_IPC(conn) && !IS_PRINT(conn)) { - set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn))); - set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn))); - set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn))); - } - - /* Invoke VFS make connection hook */ - - if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) { - DEBUG(0,("make_connection: VFS make connection failed!\n")); - change_to_root_user(); - conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; - return NULL; - } - - /* we've finished with the user stuff - go back to root */ - change_to_root_user(); - - return(conn); -} - -/*************************************************************************************** - Simple wrapper function for make_connection() to include a call to - vfs_chdir() - **************************************************************************************/ - -connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, - const char *dev, uint16 vuid, NTSTATUS *status) -{ - connection_struct *conn = NULL; - - conn = make_connection(service_in, password, dev, vuid, status); - - /* - * make_connection() does not change the directory for us any more - * so we have to do it as a separate step --jerry - */ - - if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) { - DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n", - conn->connectpath,strerror(errno))); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; - return NULL; - } - - return conn; -} - -/**************************************************************************** - Make a connection to a service. - * - * @param service -****************************************************************************/ - -connection_struct *make_connection(const char *service_in, DATA_BLOB password, - const char *pdev, uint16 vuid, NTSTATUS *status) -{ - uid_t euid; - user_struct *vuser = NULL; - fstring service; - fstring dev; - int snum = -1; - - fstrcpy(dev, pdev); - - /* 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"); - } - - if(lp_security() != SEC_SHARE) { - vuser = get_valid_user_struct(vuid); - if (!vuser) { - DEBUG(1,("make_connection: refusing to connect with no session setup\n")); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } - - /* Logic to try and connect to the correct [homes] share, preferably without too many - getpwnam() lookups. This is particulary nasty for winbind usernames, where the - share name isn't the same as unix username. - - The snum of the homes share is stored on the vuser at session setup time. - */ - - if (strequal(service_in,HOMES_NAME)) { - if(lp_security() != SEC_SHARE) { - DATA_BLOB no_pw = data_blob(NULL, 0); - if (vuser->homes_snum == -1) { - DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n")); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } - DEBUG(5, ("making a connection to [homes] service created at session setup time\n")); - return make_connection_snum(vuser->homes_snum, - vuser, no_pw, - dev, status); - } else { - /* Security = share. Try with current_user_info.smb_name - * as the username. */ - if (*current_user_info.smb_name) { - fstring unix_username; - fstrcpy(unix_username, - current_user_info.smb_name); - map_username(unix_username); - snum = find_service(unix_username); - } - if (snum != -1) { - DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in)); - return make_connection_snum(snum, NULL, - password, - dev, status); - } - } - } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1) - && strequal(service_in, lp_servicename(vuser->homes_snum))) { - DATA_BLOB no_pw = data_blob(NULL, 0); - DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in)); - return make_connection_snum(vuser->homes_snum, - vuser, no_pw, - dev, status); - } - - fstrcpy(service, service_in); - - strlower_m(service); - - snum = find_service(service); - - if (snum < 0) { - if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) { - DEBUG(3,("refusing IPC connection to %s\n", service)); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - - DEBUG(0,("%s (%s) couldn't find service %s\n", - get_remote_machine_name(), client_addr(), service)); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } - - /* Handle non-Dfs clients attempting connections to msdfs proxy */ - if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) { - DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service)); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } - - DEBUG(5, ("making a connection to 'normal' service %s\n", service)); - - return make_connection_snum(snum, vuser, - password, - dev, status); -} - -/**************************************************************************** -close a cnum -****************************************************************************/ -void close_cnum(connection_struct *conn, uint16 vuid) -{ - DirCacheFlush(SNUM(conn)); - - change_to_root_user(); - - DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n", - get_remote_machine_name(),conn->client_address, - lp_servicename(SNUM(conn)))); - - /* Call VFS disconnect hook */ - SMB_VFS_DISCONNECT(conn); - - yield_connection(conn, lp_servicename(SNUM(conn))); - - file_close_conn(conn); - dptr_closecnum(conn); - - /* make sure we leave the directory available for unmount */ - vfs_ChDir(conn, "/"); - - /* execute any "postexec = " line */ - if (*lp_postexec(SNUM(conn)) && - change_to_user(conn, vuid)) { - pstring cmd; - pstrcpy(cmd,lp_postexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); - smbrun(cmd,NULL); - change_to_root_user(); - } - - change_to_root_user(); - /* execute any "root postexec = " line */ - if (*lp_rootpostexec(SNUM(conn))) { - pstring cmd; - pstrcpy(cmd,lp_rootpostexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); - smbrun(cmd,NULL); - } - - conn_free(conn); -} diff --git a/source/smbd/session.c b/source/smbd/session.c deleted file mode 100644 index 61118f13dd9..00000000000 --- a/source/smbd/session.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - Unix SMB/CIFS implementation. - session handling for utmp and PAM - Copyright (C) tridge@samba.org 2001 - Copyright (C) abartlet@pcug.org.au 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* a "session" is claimed when we do a SessionSetupX operation - and is yielded when the corresponding vuid is destroyed. - - sessions are used to populate utmp and PAM session structures -*/ - -#include "includes.h" - -static TDB_CONTEXT *tdb; - -BOOL session_init(void) -{ - if (tdb) - return True; - - tdb = tdb_open_ex(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, - O_RDWR | O_CREAT, 0644, smbd_tdb_log); - if (!tdb) { - DEBUG(1,("session_init: failed to open sessionid tdb\n")); - return False; - } - - return True; -} - -/* called when a session is created */ -BOOL session_claim(user_struct *vuser) -{ - int i = 0; - TDB_DATA data; - struct sockaddr sa; - struct in_addr *client_ip; - struct sessionid sessionid; - uint32 pid = (uint32)sys_getpid(); - TDB_DATA key; - fstring keystr; - char * hostname; - int tdb_store_flag; /* If using utmp, we do an inital 'lock hold' store, - but we don't need this if we are just using the - (unique) pid/vuid combination */ - - vuser->session_keystr = NULL; - - /* don't register sessions for the guest user - its just too - expensive to go through pam session code for browsing etc */ - if (vuser->guest) { - return True; - } - - if (!session_init()) - return False; - - ZERO_STRUCT(sessionid); - - data.dptr = NULL; - data.dsize = 0; - - if (lp_utmp()) { - for (i=1;i<MAX_SESSION_ID;i++) { - slprintf(keystr, sizeof(keystr)-1, "ID/%d", i); - key.dptr = keystr; - key.dsize = strlen(keystr)+1; - - if (tdb_store(tdb, key, data, TDB_INSERT) == 0) break; - } - - if (i == MAX_SESSION_ID) { - DEBUG(1,("session_claim: out of session IDs (max is %d)\n", - MAX_SESSION_ID)); - return False; - } - slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_UTMP_TEMPLATE, i); - tdb_store_flag = TDB_MODIFY; - } else - { - slprintf(keystr, sizeof(keystr)-1, "ID/%lu/%u", - (long unsigned int)sys_getpid(), - vuser->vuid); - slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, - SESSION_TEMPLATE, (long unsigned int)sys_getpid(), - vuser->vuid); - - key.dptr = keystr; - key.dsize = strlen(keystr)+1; - - tdb_store_flag = TDB_REPLACE; - } - - /* If 'hostname lookup' == yes, then do the DNS lookup. This is - needed because utmp and PAM both expect DNS names - - client_name() handles this case internally. - */ - - hostname = client_name(); - if (strcmp(hostname, "UNKNOWN") == 0) { - hostname = client_addr(); - } - - fstrcpy(sessionid.username, vuser->user.unix_name); - fstrcpy(sessionid.hostname, hostname); - sessionid.id_num = i; /* Only valid for utmp sessions */ - sessionid.pid = pid; - sessionid.uid = vuser->uid; - sessionid.gid = vuser->gid; - fstrcpy(sessionid.remote_machine, get_remote_machine_name()); - fstrcpy(sessionid.ip_addr, client_addr()); - - client_ip = client_inaddr(&sa); - - if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) { - DEBUG(1,("pam_session rejected the session for %s [%s]\n", - sessionid.username, sessionid.id_str)); - if (tdb_store_flag == TDB_MODIFY) { - tdb_delete(tdb, key); - } - return False; - } - - data.dptr = (char *)&sessionid; - data.dsize = sizeof(sessionid); - if (tdb_store(tdb, key, data, tdb_store_flag) != 0) { - DEBUG(1,("session_claim: unable to create session id record\n")); - return False; - } - - if (lp_utmp()) { - sys_utmp_claim(sessionid.username, sessionid.hostname, - client_ip, - sessionid.id_str, sessionid.id_num); - } - - vuser->session_keystr = strdup(keystr); - if (!vuser->session_keystr) { - DEBUG(0, ("session_claim: strdup() failed for session_keystr\n")); - return False; - } - return True; -} - -/* called when a session is destroyed */ -void session_yield(user_struct *vuser) -{ - TDB_DATA dbuf; - struct sessionid sessionid; - struct in_addr *client_ip; - TDB_DATA key; - - if (!tdb) return; - - if (!vuser->session_keystr) { - return; - } - - key.dptr = vuser->session_keystr; - key.dsize = strlen(vuser->session_keystr)+1; - - dbuf = tdb_fetch(tdb, key); - - if (dbuf.dsize != sizeof(sessionid)) - return; - - memcpy(&sessionid, dbuf.dptr, sizeof(sessionid)); - - client_ip = interpret_addr2(sessionid.ip_addr); - - SAFE_FREE(dbuf.dptr); - - if (lp_utmp()) { - sys_utmp_yield(sessionid.username, sessionid.hostname, - client_ip, - sessionid.id_str, sessionid.id_num); - } - - smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname); - - tdb_delete(tdb, key); -} - -static BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state) -{ - if (!session_init()) { - DEBUG(3, ("No tdb opened\n")); - return False; - } - - tdb_traverse(tdb, fn, state); - return True; -} - -struct session_list { - int count; - struct sessionid *sessions; -}; - -static int gather_sessioninfo(TDB_CONTEXT *stdb, TDB_DATA kbuf, TDB_DATA dbuf, - void *state) -{ - struct session_list *sesslist = (struct session_list *) state; - const struct sessionid *current = (const struct sessionid *) dbuf.dptr; - - sesslist->count += 1; - sesslist->sessions = REALLOC(sesslist->sessions, sesslist->count * - sizeof(struct sessionid)); - - memcpy(&sesslist->sessions[sesslist->count - 1], current, - sizeof(struct sessionid)); - DEBUG(7,("gather_sessioninfo session from %s@%s\n", - current->username, current->remote_machine)); - return 0; -} - -int list_sessions(struct sessionid **session_list) -{ - struct session_list sesslist; - - sesslist.count = 0; - sesslist.sessions = NULL; - - if (!session_traverse(gather_sessioninfo, (void *) &sesslist)) { - DEBUG(3, ("Session traverse failed\n")); - SAFE_FREE(sesslist.sessions); - *session_list = NULL; - return 0; - } - - *session_list = sesslist.sessions; - return sesslist.count; -} diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c deleted file mode 100644 index b8777be6971..00000000000 --- a/source/smbd/sesssetup.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - Unix SMB/CIFS implementation. - handle SMBsessionsetup - Copyright (C) Andrew Tridgell 1998-2001 - Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002 - Copyright (C) Luke Howard 2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -uint32 global_client_caps = 0; - -static struct auth_ntlmssp_state *global_ntlmssp_state; - -/* - on a logon error possibly map the error to success if "map to guest" - is set approriately -*/ -static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info, - const char *user, const char *domain) -{ - if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || - (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { - DEBUG(3,("No such user %s [%s] - using guest account\n", - user, domain)); - status = make_server_info_guest(server_info); - } - } - - if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { - DEBUG(3,("Registered username %s for guest access\n",user)); - status = make_server_info_guest(server_info); - } - } - - return status; -} - -/**************************************************************************** - Add the standard 'Samba' signature to the end of the session setup. -****************************************************************************/ - -static int add_signature(char *outbuf, char *p) -{ - char *start = p; - fstring lanman; - - fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING); - - p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE); - p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE); - p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE); - - return PTR_DIFF(p, start); -} - -/**************************************************************************** - Send a security blob via a session setup reply. -****************************************************************************/ - -static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, - DATA_BLOB blob, NTSTATUS nt_status) -{ - char *p; - - set_message(outbuf,4,0,True); - - nt_status = nt_status_squash(nt_status); - SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status)); - SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */ - SSVAL(outbuf, smb_vwv3, blob.length); - p = smb_buf(outbuf); - - /* should we cap this? */ - memcpy(p, blob.data, blob.length); - p += blob.length; - - p += add_signature( outbuf, p ); - - set_message_end(outbuf,p); - - return send_smb(smbd_server_fd(),outbuf); -} - -/**************************************************************************** - Do a 'guest' logon, getting back the -****************************************************************************/ - -static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) -{ - struct auth_context *auth_context; - auth_usersupplied_info *user_info = NULL; - - NTSTATUS nt_status; - unsigned char chal[8]; - - ZERO_STRUCT(chal); - - DEBUG(3,("Got anonymous request\n")); - - if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) { - return nt_status; - } - - if (!make_user_info_guest(&user_info)) { - (auth_context->free)(&auth_context); - return NT_STATUS_NO_MEMORY; - } - - nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info); - (auth_context->free)(&auth_context); - free_user_info(&user_info); - return nt_status; -} - - -#ifdef HAVE_KRB5 -/**************************************************************************** -reply to a session setup spnego negotiate packet for kerberos -****************************************************************************/ -static int reply_spnego_kerberos(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - DATA_BLOB *secblob) -{ - DATA_BLOB ticket; - char *client, *p, *domain; - fstring netbios_domain_name; - struct passwd *pw; - char *user; - int sess_vuid; - NTSTATUS ret; - DATA_BLOB auth_data; - DATA_BLOB ap_rep, ap_rep_wrapped, response; - auth_serversupplied_info *server_info = NULL; - DATA_BLOB session_key; - uint8 tok_id[2]; - BOOL foreign = False; - DATA_BLOB nullblob = data_blob(NULL, 0); - fstring real_username; - - ZERO_STRUCT(ticket); - ZERO_STRUCT(auth_data); - ZERO_STRUCT(ap_rep); - ZERO_STRUCT(ap_rep_wrapped); - ZERO_STRUCT(response); - - if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key); - - data_blob_free(&ticket); - - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(1,("Failed to verify incoming ticket!\n")); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - data_blob_free(&auth_data); - - DEBUG(3,("Ticket name is [%s]\n", client)); - - p = strchr_m(client, '@'); - if (!p) { - DEBUG(3,("Doesn't look like a valid principal\n")); - data_blob_free(&ap_rep); - SAFE_FREE(client); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - *p = 0; - if (!strequal(p+1, lp_realm())) { - DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1)); - if (!lp_allow_trusted_domains()) { - data_blob_free(&ap_rep); - SAFE_FREE(client); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - foreign = True; - } - - /* this gives a fully qualified user name (ie. with full realm). - that leads to very long usernames, but what else can we do? */ - - domain = p+1; - - { - /* If we have winbind running, we can (and must) shorten the - username by using the short netbios name. Otherwise we will - have inconsistent user names. With Kerberos, we get the - fully qualified realm, with ntlmssp we get the short - name. And even w2k3 does use ntlmssp if you for example - connect to an ip address. */ - - struct winbindd_request wb_request; - struct winbindd_response wb_response; - NSS_STATUS wb_result; - - ZERO_STRUCT(wb_request); - ZERO_STRUCT(wb_response); - - DEBUG(10, ("Mapping [%s] to short name\n", domain)); - - fstrcpy(wb_request.domain_name, domain); - - wb_result = winbindd_request(WINBINDD_DOMAIN_INFO, - &wb_request, &wb_response); - - if (wb_result == NSS_STATUS_SUCCESS) { - - fstrcpy(netbios_domain_name, - wb_response.data.domain_info.name); - domain = netbios_domain_name; - - DEBUG(10, ("Mapped to [%s]\n", domain)); - } else { - DEBUG(3, ("Could not find short name -- winbind " - "not running?\n")); - } - } - - asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client); - - /* lookup the passwd struct, create a new user if necessary */ - - pw = smb_getpwnam( user, real_username, True ); - - if (!pw) { - DEBUG(1,("Username %s is invalid on this system\n",user)); - SAFE_FREE(user); - SAFE_FREE(client); - data_blob_free(&ap_rep); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - /* setup the string used by %U */ - - sub_set_smb_name( real_username ); - reload_services(True); - - if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw))) - { - DEBUG(1,("make_server_info_from_pw failed!\n")); - SAFE_FREE(user); - SAFE_FREE(client); - data_blob_free(&ap_rep); - return ERROR_NT(ret); - } - - /* make_server_info_pw does not set the domain. Without this we end up - * with the local netbios name in substitutions for %D. */ - - if (server_info->sam_account != NULL) { - pdb_set_domain(server_info->sam_account, domain, PDB_SET); - } - - /* register_vuid keeps the server info */ - sess_vuid = register_vuid(server_info, session_key, nullblob, client); - - SAFE_FREE(user); - SAFE_FREE(client); - - if (sess_vuid == -1) { - ret = NT_STATUS_LOGON_FAILURE; - } else { - /* current_user_info is changed on new vuid */ - reload_services( True ); - - set_message(outbuf,4,0,True); - SSVAL(outbuf, smb_vwv3, 0); - - if (server_info->guest) { - SSVAL(outbuf,smb_vwv2,1); - } - - SSVAL(outbuf, smb_uid, sess_vuid); - - if (!server_info->guest && !srv_signing_started()) { - /* We need to start the signing engine - * here but a W2K client sends the old - * "BSRSPYL " signature instead of the - * correct one. Subsequent packets will - * be correct. - */ - srv_check_sign_mac(inbuf, False); - } - } - - /* wrap that up in a nice GSS-API wrapping */ - if (NT_STATUS_IS_OK(ret)) { - ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP); - } else { - ap_rep_wrapped = data_blob(NULL, 0); - } - response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD); - reply_sesssetup_blob(conn, outbuf, response, ret); - - data_blob_free(&ap_rep); - data_blob_free(&ap_rep_wrapped); - data_blob_free(&response); - - return -1; /* already replied */ -} -#endif - -/**************************************************************************** - Send a session setup reply, wrapped in SPNEGO. - Get vuid and check first. - End the NTLMSSP exchange context if we are OK/complete fail -***************************************************************************/ - -static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf, - AUTH_NTLMSSP_STATE **auth_ntlmssp_state, - DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) -{ - BOOL ret; - DATA_BLOB response; - struct auth_serversupplied_info *server_info = NULL; - - if (NT_STATUS_IS_OK(nt_status)) { - server_info = (*auth_ntlmssp_state)->server_info; - } else { - nt_status = do_map_to_guest(nt_status, - &server_info, - (*auth_ntlmssp_state)->ntlmssp_state->user, - (*auth_ntlmssp_state)->ntlmssp_state->domain); - } - - if (NT_STATUS_IS_OK(nt_status)) { - int sess_vuid; - DATA_BLOB nullblob = data_blob(NULL, 0); - DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); - - /* register_vuid keeps the server info */ - sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user); - (*auth_ntlmssp_state)->server_info = NULL; - - if (sess_vuid == -1) { - nt_status = NT_STATUS_LOGON_FAILURE; - } else { - - /* current_user_info is changed on new vuid */ - reload_services( True ); - - set_message(outbuf,4,0,True); - SSVAL(outbuf, smb_vwv3, 0); - - if (server_info->guest) { - SSVAL(outbuf,smb_vwv2,1); - } - - SSVAL(outbuf,smb_uid,sess_vuid); - - if (!server_info->guest && !srv_signing_started()) { - /* We need to start the signing engine - * here but a W2K client sends the old - * "BSRSPYL " signature instead of the - * correct one. Subsequent packets will - * be correct. - */ - - srv_check_sign_mac(inbuf, False); - } - } - } - - response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP); - ret = reply_sesssetup_blob(conn, outbuf, response, nt_status); - data_blob_free(&response); - - /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us, - and the other end, that we are not finished yet. */ - - if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - auth_ntlmssp_end(auth_ntlmssp_state); - } - - return ret; -} - -/**************************************************************************** - Reply to a session setup spnego negotiate packet. -****************************************************************************/ - -static int reply_spnego_negotiate(connection_struct *conn, - char *inbuf, - char *outbuf, - int length, int bufsize, - DATA_BLOB blob1) -{ - char *OIDs[ASN1_MAX_OIDS]; - DATA_BLOB secblob; - int i; - DATA_BLOB chal; - BOOL got_kerberos = False; - NTSTATUS nt_status; - - /* parse out the OIDs and the first sec blob */ - if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - /* only look at the first OID for determining the mechToken -- - accoirding to RFC2478, we should choose the one we want - and renegotiate, but i smell a client bug here.. - - Problem observed when connecting to a member (samba box) - of an AD domain as a user in a Samba domain. Samba member - server sent back krb5/mskrb5/ntlmssp as mechtypes, but the - client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an - NTLMSSP mechtoken. --jerry */ - - if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || - strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) { - got_kerberos = True; - } - - for (i=0;OIDs[i];i++) { - DEBUG(3,("Got OID %s\n", OIDs[i])); - free(OIDs[i]); - } - DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length)); - -#ifdef HAVE_KRB5 - if (got_kerberos && (SEC_ADS == lp_security())) { - int ret = reply_spnego_kerberos(conn, inbuf, outbuf, - length, bufsize, &secblob); - data_blob_free(&secblob); - return ret; - } -#endif - - if (global_ntlmssp_state) { - auth_ntlmssp_end(&global_ntlmssp_state); - } - - nt_status = auth_ntlmssp_start(&global_ntlmssp_state); - if (!NT_STATUS_IS_OK(nt_status)) { - return ERROR_NT(nt_status); - } - - nt_status = auth_ntlmssp_update(global_ntlmssp_state, - secblob, &chal); - - data_blob_free(&secblob); - - reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state, - &chal, nt_status); - - data_blob_free(&chal); - - /* already replied */ - return -1; -} - -/**************************************************************************** - Reply to a session setup spnego auth packet. -****************************************************************************/ - -static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, - int length, int bufsize, - DATA_BLOB blob1) -{ - DATA_BLOB auth, auth_reply; - NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; - - if (!spnego_parse_auth(blob1, &auth)) { -#if 0 - file_save("auth.dat", blob1.data, blob1.length); -#endif - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - if (!global_ntlmssp_state) { - /* auth before negotiatiate? */ - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - nt_status = auth_ntlmssp_update(global_ntlmssp_state, - auth, &auth_reply); - - data_blob_free(&auth); - - reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state, - &auth_reply, nt_status); - - data_blob_free(&auth_reply); - - /* and tell smbd that we have already replied to this packet */ - return -1; -} - -/**************************************************************************** - Reply to a session setup command. -****************************************************************************/ - -static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf, - char *outbuf, - int length,int bufsize) -{ - uint8 *p; - DATA_BLOB blob1; - int ret; - size_t bufrem; - fstring native_os, native_lanman, primary_domain; - char *p2; - uint16 data_blob_len = SVAL(inbuf, smb_vwv7); - enum remote_arch_types ra_type = get_remote_arch(); - - DEBUG(3,("Doing spnego session setup\n")); - - if (global_client_caps == 0) { - global_client_caps = IVAL(inbuf,smb_vwv10); - - if (!(global_client_caps & CAP_STATUS32)) { - remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); - } - - } - - p = (uint8 *)smb_buf(inbuf); - - if (data_blob_len == 0) { - /* an invalid request */ - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - bufrem = smb_bufrem(inbuf, p); - /* pull the spnego blob */ - blob1 = data_blob(p, MIN(bufrem, data_blob_len)); - -#if 0 - file_save("negotiate.dat", blob1.data, blob1.length); -#endif - - p2 = inbuf + smb_vwv13 + data_blob_len; - p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE); - p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE); - p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE); - DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", - native_os, native_lanman, primary_domain)); - - if ( ra_type == RA_WIN2K ) { - /* Windows 2003 doesn't set the native lanman string, - but does set primary domain which is a bug I think */ - - if ( !strlen(native_lanman) ) - ra_lanman_string( primary_domain ); - else - ra_lanman_string( native_lanman ); - } - - if (blob1.data[0] == ASN1_APPLICATION(0)) { - /* its a negTokenTarg packet */ - ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1); - data_blob_free(&blob1); - return ret; - } - - if (blob1.data[0] == ASN1_CONTEXT(1)) { - /* its a auth packet */ - ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1); - data_blob_free(&blob1); - return ret; - } - - /* what sort of packet is this? */ - DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n")); - - data_blob_free(&blob1); - - return ERROR_NT(NT_STATUS_LOGON_FAILURE); -} - -/**************************************************************************** - On new VC == 0, shutdown *all* old connections and users. - It seems that only NT4.x does this. At W2K and above (XP etc.). - a new session setup with VC==0 is ignored. -****************************************************************************/ - -static void setup_new_vc_session(void) -{ - DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n")); -#if 0 - conn_close_all(); - invalidate_all_vuids(); -#endif -} - -/**************************************************************************** - Reply to a session setup command. -****************************************************************************/ - -int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, - int length,int bufsize) -{ - int sess_vuid; - int smb_bufsize; - DATA_BLOB lm_resp; - DATA_BLOB nt_resp; - DATA_BLOB plaintext_password; - fstring user; - fstring sub_user; /* Sainitised username for substituion */ - fstring domain; - fstring native_os; - fstring native_lanman; - fstring primary_domain; - static BOOL done_sesssetup = False; - extern BOOL global_encrypted_passwords_negotiated; - extern BOOL global_spnego_negotiated; - extern int Protocol; - extern int max_send; - - auth_usersupplied_info *user_info = NULL; - extern struct auth_context *negprot_global_auth_context; - auth_serversupplied_info *server_info = NULL; - - NTSTATUS nt_status; - - BOOL doencrypt = global_encrypted_passwords_negotiated; - - DATA_BLOB session_key; - - START_PROFILE(SMBsesssetupX); - - ZERO_STRUCT(lm_resp); - ZERO_STRUCT(nt_resp); - ZERO_STRUCT(plaintext_password); - - DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2))); - - /* a SPNEGO session setup has 12 command words, whereas a normal - NT1 session setup has 13. See the cifs spec. */ - if (CVAL(inbuf, smb_wct) == 12 && - (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { - if (!global_spnego_negotiated) { - DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n")); - return ERROR_NT(NT_STATUS_UNSUCCESSFUL); - } - - if (SVAL(inbuf,smb_vwv4) == 0) { - setup_new_vc_session(); - } - return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize); - } - - smb_bufsize = SVAL(inbuf,smb_vwv2); - - if (Protocol < PROTOCOL_NT1) { - uint16 passlen1 = SVAL(inbuf,smb_vwv7); - if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) { - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - if (doencrypt) { - lm_resp = data_blob(smb_buf(inbuf), passlen1); - } else { - plaintext_password = data_blob(smb_buf(inbuf), passlen1+1); - /* Ensure null termination */ - plaintext_password.data[passlen1] = 0; - } - - srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE); - *domain = 0; - - } else { - uint16 passlen1 = SVAL(inbuf,smb_vwv7); - uint16 passlen2 = SVAL(inbuf,smb_vwv8); - enum remote_arch_types ra_type = get_remote_arch(); - char *p = smb_buf(inbuf); - char *save_p = smb_buf(inbuf); - uint16 byte_count; - - - if(global_client_caps == 0) { - global_client_caps = IVAL(inbuf,smb_vwv11); - - if (!(global_client_caps & CAP_STATUS32)) { - remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); - } - - /* client_caps is used as final determination if client is NT or Win95. - This is needed to return the correct error codes in some - circumstances. - */ - - if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { - if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { - set_remote_arch( RA_WIN95); - } - } - } - - if (!doencrypt) { - /* both Win95 and WinNT stuff up the password lengths for - non-encrypting systems. Uggh. - - if passlen1==24 its a win95 system, and its setting the - password length incorrectly. Luckily it still works with the - default code because Win95 will null terminate the password - anyway - - if passlen1>0 and passlen2>0 then maybe its a NT box and its - setting passlen2 to some random value which really stuffs - things up. we need to fix that one. */ - - if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) - passlen2 = 0; - } - - /* check for nasty tricks */ - if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) { - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) { - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - /* Save the lanman2 password and the NT md4 password. */ - - if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) { - doencrypt = False; - } - - if (doencrypt) { - lm_resp = data_blob(p, passlen1); - nt_resp = data_blob(p+passlen1, passlen2); - } else { - pstring pass; - BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS; - - if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) { - /* NT4.0 stuffs up plaintext unicode password lengths... */ - srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1, - sizeof(pass), passlen1, STR_TERMINATE); - } else { - srvstr_pull(inbuf, pass, smb_buf(inbuf), - sizeof(pass), unic ? passlen2 : passlen1, - STR_TERMINATE); - } - plaintext_password = data_blob(pass, strlen(pass)+1); - } - - p += passlen1 + passlen2; - p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE); - p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE); - p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE); - p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE); - - /* not documented or decoded by Ethereal but there is one more string - in the extra bytes which is the same as the PrimaryDomain when using - extended security. Windows NT 4 and 2003 use this string to store - the native lanman string. Windows 9x does not include a string here - at all so we have to check if we have any extra bytes left */ - - byte_count = SVAL(inbuf, smb_vwv13); - if ( PTR_DIFF(p, save_p) < byte_count) - p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE); - else - fstrcpy( primary_domain, "null" ); - - DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", - domain, native_os, native_lanman, primary_domain)); - - if ( ra_type == RA_WIN2K ) { - if ( strlen(native_lanman) == 0 ) - ra_lanman_string( primary_domain ); - else - ra_lanman_string( native_lanman ); - } - - } - - if (SVAL(inbuf,smb_vwv4) == 0) { - setup_new_vc_session(); - } - - DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name())); - - if (*user) { - if (global_spnego_negotiated) { - - /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */ - - DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n")); - return ERROR_NT(NT_STATUS_UNSUCCESSFUL); - } - fstrcpy(sub_user, user); - - /* setup the string used by %U */ - sub_set_smb_name(user); - } else { - fstrcpy(sub_user, lp_guestaccount()); - } - - sub_set_smb_name(sub_user); - - reload_services(True); - - if (lp_security() == SEC_SHARE) { - /* in share level we should ignore any passwords */ - - data_blob_free(&lm_resp); - data_blob_free(&nt_resp); - data_blob_clear_free(&plaintext_password); - - map_username(sub_user); - add_session_user(sub_user); - /* Then force it to null for the benfit of the code below */ - *user = 0; - } - - if (!*user) { - - nt_status = check_guest_password(&server_info); - - } else if (doencrypt) { - if (!negprot_global_auth_context) { - DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n")); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - nt_status = make_user_info_for_reply_enc(&user_info, user, domain, - lm_resp, nt_resp); - if (NT_STATUS_IS_OK(nt_status)) { - nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, - user_info, - &server_info); - } - } else { - struct auth_context *plaintext_auth_context = NULL; - const uint8 *chal; - if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) { - chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context); - - if (!make_user_info_for_reply(&user_info, - user, domain, chal, - plaintext_password)) { - nt_status = NT_STATUS_NO_MEMORY; - } - - if (NT_STATUS_IS_OK(nt_status)) { - nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, - user_info, - &server_info); - - (plaintext_auth_context->free)(&plaintext_auth_context); - } - } - } - - free_user_info(&user_info); - - if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = do_map_to_guest(nt_status, &server_info, user, domain); - } - - if (!NT_STATUS_IS_OK(nt_status)) { - data_blob_free(&nt_resp); - data_blob_free(&lm_resp); - data_blob_clear_free(&plaintext_password); - return ERROR_NT(nt_status_squash(nt_status)); - } - - if (server_info->nt_session_key.data) { - session_key = data_blob(server_info->nt_session_key.data, server_info->nt_session_key.length); - } else if (server_info->lm_session_key.length >= 8 && lm_resp.length == 24) { - session_key = data_blob(NULL, 16); - SMBsesskeygen_lmv1(server_info->lm_session_key.data, lm_resp.data, - session_key.data); - } else { - session_key = data_blob(NULL, 0); - } - - data_blob_free(&lm_resp); - data_blob_clear_free(&plaintext_password); - - /* it's ok - setup a reply */ - set_message(outbuf,3,0,True); - if (Protocol >= PROTOCOL_NT1) { - char *p = smb_buf( outbuf ); - p += add_signature( outbuf, p ); - set_message_end( outbuf, p ); - /* perhaps grab OS version here?? */ - } - - if (server_info->guest) { - SSVAL(outbuf,smb_vwv2,1); - } - - /* register the name and uid as being validated, so further connections - to a uid can get through without a password, on the same VC */ - - /* register_vuid keeps the server info */ - sess_vuid = register_vuid(server_info, session_key, nt_resp, sub_user); - data_blob_free(&nt_resp); - - if (sess_vuid == -1) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - /* current_user_info is changed on new vuid */ - reload_services( True ); - - if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) { - exit_server("reply_sesssetup_and_X: bad smb signature"); - } - - SSVAL(outbuf,smb_uid,sess_vuid); - SSVAL(inbuf,smb_uid,sess_vuid); - - if (!done_sesssetup) - max_send = MIN(max_send,smb_bufsize); - - done_sesssetup = True; - - END_PROFILE(SMBsesssetupX); - return chain_reply(inbuf,outbuf,length,bufsize); -} diff --git a/source/smbd/srvstr.c b/source/smbd/srvstr.c deleted file mode 100644 index 409fd30a679..00000000000 --- a/source/smbd/srvstr.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - Unix SMB/CIFS implementation. - server specific string routines - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -extern int max_send; - -/* Make sure we can't write a string past the end of the buffer */ - -size_t srvstr_push_fn(const char *function, unsigned int line, - const char *base_ptr, void *dest, - const char *src, int dest_len, int flags) -{ - size_t buf_used = PTR_DIFF(dest, base_ptr); - if (dest_len == -1) { - if (((ptrdiff_t)dest < (ptrdiff_t)base_ptr) || (buf_used > (size_t)max_send)) { -#if 0 - DEBUG(0, ("Pushing string of 'unlimited' length into non-SMB buffer!\n")); -#endif - return push_string_fn(function, line, base_ptr, dest, src, -1, flags); - } - return push_string_fn(function, line, base_ptr, dest, src, max_send - buf_used, flags); - } - - /* 'normal' push into size-specified buffer */ - return push_string_fn(function, line, base_ptr, dest, src, dest_len, flags); -} diff --git a/source/smbd/statcache.c b/source/smbd/statcache.c deleted file mode 100644 index d996f5e4938..00000000000 --- a/source/smbd/statcache.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - Unix SMB/CIFS implementation. - stat cache code - Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Jeremy Allison 1999-2000 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern BOOL case_sensitive; - -/**************************************************************************** - Stat cache code used in unix_convert. -*****************************************************************************/ - -typedef struct { - char *original_path; - char *translated_path; - size_t translated_path_length; - char names[2]; /* This is extended via malloc... */ -} stat_cache_entry; - -#define INIT_STAT_CACHE_SIZE 512 -static hash_table stat_cache; - -/** - * Add an entry into the stat cache. - * - * @param full_orig_name The original name as specified by the client - * @param orig_translated_path The name on our filesystem. - * - * @note Only the first strlen(orig_translated_path) characters are stored - * into the cache. This means that full_orig_name will be internally - * truncated. - * - */ - -void stat_cache_add( const char *full_orig_name, const char *orig_translated_path) -{ - stat_cache_entry *scp; - stat_cache_entry *found_scp; - char *translated_path; - size_t translated_path_length; - - char *original_path; - size_t original_path_length; - - hash_element *hash_elem; - - if (!lp_stat_cache()) - return; - - /* - * Don't cache trivial valid directory entries such as . and .. - */ - - if((*full_orig_name == '\0') || (full_orig_name[0] == '.' && - ((full_orig_name[1] == '\0') || - (full_orig_name[1] == '.' && full_orig_name[1] == '\0')))) - return; - - /* - * If we are in case insentive mode, we don't need to - * store names that need no translation - else, it - * would be a waste. - */ - - if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0)) - return; - - /* - * Remove any trailing '/' characters from the - * translated path. - */ - - translated_path = strdup(orig_translated_path); - if (!translated_path) - return; - - translated_path_length = strlen(translated_path); - - if(translated_path[translated_path_length-1] == '/') { - translated_path[translated_path_length-1] = '\0'; - translated_path_length--; - } - - if(case_sensitive) { - original_path = strdup(full_orig_name); - } else { - original_path = strdup_upper(full_orig_name); - } - - if (!original_path) { - SAFE_FREE(translated_path); - return; - } - - original_path_length = strlen(original_path); - - if(original_path[original_path_length-1] == '/') { - original_path[original_path_length-1] = '\0'; - original_path_length--; - } - - if (original_path_length != translated_path_length) { - if (original_path_length < translated_path_length) { - DEBUG(0, ("OOPS - tried to store stat cache entry for weird length paths [%s] %lu and [%s] %lu)!\n", - original_path, (unsigned long)original_path_length, translated_path, (unsigned long)translated_path_length)); - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - - /* we only want to store the first part of original_path, - up to the length of translated_path */ - - original_path[translated_path_length] = '\0'; - original_path_length = translated_path_length; - } - - /* - * Check this name doesn't exist in the cache before we - * add it. - */ - - if ((hash_elem = hash_lookup(&stat_cache, original_path))) { - found_scp = (stat_cache_entry *)(hash_elem->value); - if (strcmp((found_scp->translated_path), orig_translated_path) == 0) { - /* already in hash table */ - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - /* hash collision - remove before we re-add */ - hash_remove(&stat_cache, hash_elem); - } - - /* - * New entry. - */ - - if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry) - +original_path_length - +translated_path_length)) == NULL) { - DEBUG(0,("stat_cache_add: Out of memory !\n")); - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - - scp->original_path = scp->names; - /* pointer into the structure... */ - scp->translated_path = scp->names + original_path_length + 1; - safe_strcpy(scp->original_path, original_path, original_path_length); - safe_strcpy(scp->translated_path, translated_path, translated_path_length); - scp->translated_path_length = translated_path_length; - - hash_insert(&stat_cache, (char *)scp, original_path); - - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - - DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->original_path, scp->translated_path)); -} - -/** - * Look through the stat cache for an entry - * - * The hash-table's internals will promote it to the top if found. - * - * @param conn A connection struct to do the stat() with. - * @param name The path we are attempting to cache, modified by this routine - * to be correct as far as the cache can tell us - * @param dirpath The path as far as the stat cache told us. - * @param start A pointer into name, for where to 'start' in fixing the rest of the name up. - * @param psd A stat buffer, NOT from the cache, but just a side-effect. - * - * @return True if we translated (and did a scuccessful stat on) the entire name. - * - */ - -BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, - char **start, SMB_STRUCT_STAT *pst) -{ - stat_cache_entry *scp; - char *chk_name; - size_t namelen; - hash_element *hash_elem; - char *sp; - BOOL sizechanged = False; - unsigned int num_components = 0; - - if (!lp_stat_cache()) - return False; - - namelen = strlen(name); - - *start = name; - - DO_PROFILE_INC(statcache_lookups); - - /* - * Don't lookup trivial valid directory entries. - */ - if((*name == '\0') || (name[0] == '.' && - ((name[1] == '\0') || - (name[1] == '.' && name[1] == '\0')))) - return False; - - if (case_sensitive) { - chk_name = strdup(name); - if (!chk_name) { - DEBUG(0, ("stat_cache_lookup: strdup failed!\n")); - return False; - } - - } else { - chk_name = strdup_upper(name); - if (!chk_name) { - DEBUG(0, ("stat_cache_lookup: strdup_upper failed!\n")); - return False; - } - - /* - * In some language encodings the length changes - * if we uppercase. We need to treat this differently - * below. - */ - if (strlen(chk_name) != namelen) - sizechanged = True; - } - - while (1) { - hash_elem = hash_lookup(&stat_cache, chk_name); - if(hash_elem == NULL) { - DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n", chk_name )); - /* - * Didn't find it - remove last component for next try. - */ - sp = strrchr_m(chk_name, '/'); - if (sp) { - *sp = '\0'; - /* - * Count the number of times we have done this, - * we'll need it when reconstructing the string. - */ - if (sizechanged) - num_components++; - - } else { - /* - * We reached the end of the name - no match. - */ - DO_PROFILE_INC(statcache_misses); - SAFE_FREE(chk_name); - return False; - } - if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0) - || (strcmp(chk_name, "..") == 0)) { - DO_PROFILE_INC(statcache_misses); - SAFE_FREE(chk_name); - return False; - } - } else { - scp = (stat_cache_entry *)(hash_elem->value); - DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] -> [%s]\n", chk_name, scp->translated_path )); - DO_PROFILE_INC(statcache_hits); - if(SMB_VFS_STAT(conn,scp->translated_path, pst) != 0) { - /* Discard this entry - it doesn't exist in the filesystem. */ - hash_remove(&stat_cache, hash_elem); - SAFE_FREE(chk_name); - return False; - } - - if (!sizechanged) { - memcpy(name, scp->translated_path, MIN(sizeof(pstring)-1, scp->translated_path_length)); - } else if (num_components == 0) { - pstrcpy(name, scp->translated_path); - } else { - sp = strnrchr_m(name, '/', num_components); - if (sp) { - pstring last_component; - pstrcpy(last_component, sp); - pstrcpy(name, scp->translated_path); - pstrcat(name, last_component); - } else { - pstrcpy(name, scp->translated_path); - } - } - - /* set pointer for 'where to start' on fixing the rest of the name */ - *start = &name[scp->translated_path_length]; - if(**start == '/') - ++*start; - - pstrcpy(dirpath, scp->translated_path); - SAFE_FREE(chk_name); - return (namelen == scp->translated_path_length); - } - } -} - -/*************************************************************************** ** - * Initializes or clears the stat cache. - * - * Input: none. - * Output: none. - * - * ************************************************************************** ** - */ -BOOL reset_stat_cache( void ) -{ - static BOOL initialised; - if (!lp_stat_cache()) - return True; - - if (initialised) { - hash_clear(&stat_cache); - } - - initialised = hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, - (compare_function)(strcmp)); - return initialised; -} diff --git a/source/smbd/tdbutil.c b/source/smbd/tdbutil.c deleted file mode 100644 index cafcde20374..00000000000 --- a/source/smbd/tdbutil.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Main SMB server routines - Copyright (C) Jeremy Allison 2003 - Copyright (C) Gerald (Jerry) Carter 2004 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - -/********************************************************************** - logging function used by smbd to detect and remove corrupted tdb's -**********************************************************************/ - -void smbd_tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...) -{ - va_list ap; - char *ptr = NULL; - BOOL decrement_smbd_count; - - va_start(ap, format); - vasprintf(&ptr, format, ap); - va_end(ap); - - if (!ptr || !*ptr) - return; - - DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unnamed", ptr)); - - if (tdb->ecode == TDB_ERR_CORRUPT) { - int ret; - - DEBUG(0,("tdb_log: TDB %s is corrupt. Removing file and stopping this process.\n", - tdb->name )); - - become_root(); - ret = unlink(tdb->name); - if ( ret ) { - DEBUG(0,("ERROR: %s\n", strerror(errno))); - } - unbecome_root(); - - - /* if its not connections.tdb, then make sure we decrement the - smbd count. If connections.tdb is bad, there's nothing we - can do and everything will eventually shut down or clean - up anyways */ - - if ( strcmp(tdb->name, lock_path("connections.tdb")) == 0 ) - decrement_smbd_count = False; - else - decrement_smbd_count = True; - - /* now die */ - - smb_panic2("corrupt tdb\n", decrement_smbd_count ); - } - - if (tdb->ecode == TDB_ERR_IO) - { - if ( strcmp(tdb->name, lock_path("connections.tdb")) == 0 ) - decrement_smbd_count = False; - else - decrement_smbd_count = True; - - smb_panic2( "i/o error on tdb.\n", decrement_smbd_count ); - } - - SAFE_FREE(ptr); -} - diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c deleted file mode 100644 index a88722edde5..00000000000 --- a/source/smbd/trans2.c +++ /dev/null @@ -1,4165 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB transaction2 handling - Copyright (C) Jeremy Allison 1994-2003 - Copyright (C) Stefan (metze) Metzmacher 2003 - - Extensively modified by Andrew Tridgell, 1995 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern int Protocol; -extern BOOL case_sensitive; -extern int smb_read_error; -extern fstring local_machine; -extern int global_oplock_break; -extern uint32 global_client_caps; -extern struct current_user current_user; - -#define get_file_size(sbuf) ((sbuf).st_size) - -/* given a stat buffer return the allocated size on disk, taking into - account sparse files */ -SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf) -{ - SMB_BIG_UINT ret; -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks; -#else - ret = (SMB_BIG_UINT)get_file_size(*sbuf); -#endif - if (!ret && fsp && fsp->initial_allocation_size) - ret = fsp->initial_allocation_size; - ret = SMB_ROUNDUP(ret,SMB_ROUNDUP_ALLOCATION_SIZE); - return ret; -} - -/**************************************************************************** - Utility functions for dealing with extended attributes. -****************************************************************************/ - -static const char *prohibited_ea_names[] = { - SAMBA_POSIX_INHERITANCE_EA_NAME, - SAMBA_XATTR_DOS_ATTRIB, - NULL -}; - -/**************************************************************************** - Refuse to allow clients to overwrite our private xattrs. -****************************************************************************/ - -static BOOL samba_private_attr_name(const char *unix_ea_name) -{ - int i; - - for (i = 0; prohibited_ea_names[i]; i++) { - if (strequal( prohibited_ea_names[i], unix_ea_name)) - return True; - } - return False; -} - -struct ea_list { - struct ea_list *next, *prev; - struct ea_struct ea; -}; - -/**************************************************************************** - Get one EA value. Fill in a struct ea_struct. -****************************************************************************/ - -static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, - const char *fname, char *ea_name, struct ea_struct *pea) -{ - /* Get the value of this xattr. Max size is 64k. */ - size_t attr_size = 256; - char *val = NULL; - ssize_t sizeret; - - again: - - val = talloc_realloc(mem_ctx, val, attr_size); - if (!val) { - return False; - } - - if (fsp && fsp->fd != -1) { - sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fd, ea_name, val, attr_size); - } else { - sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size); - } - - if (sizeret == -1 && errno == ERANGE && attr_size != 65536) { - attr_size = 65536; - goto again; - } - - if (sizeret == -1) { - return False; - } - - DEBUG(10,("get_ea_value: EA %s is of length %d: ", ea_name, sizeret)); - dump_data(10, val, sizeret); - - pea->flags = 0; - if (strnequal(ea_name, "user.", 5)) { - pea->name = &ea_name[5]; - } else { - pea->name = ea_name; - } - pea->value.data = val; - pea->value.length = (size_t)sizeret; - return True; -} - -/**************************************************************************** - Return a linked list of the total EA's. Plus a guess as to the total size - (NB. The is not the total size on the wire - we need to convert to DOS - codepage for that). -****************************************************************************/ - -static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, const char *fname, size_t *pea_total_len) -{ - /* Get a list of all xattrs. Max namesize is 64k. */ - size_t ea_namelist_size = 1024; - char *ea_namelist; - char *p; - ssize_t sizeret; - int i; - struct ea_list *ea_list_head = NULL; - - if (pea_total_len) { - *pea_total_len = 0; - } - - if (!lp_ea_support(SNUM(conn))) { - return NULL; - } - - for (i = 0, ea_namelist = talloc(mem_ctx, ea_namelist_size); i < 6; - ea_namelist = talloc_realloc(mem_ctx, ea_namelist, ea_namelist_size), i++) { - if (fsp && fsp->fd != -1) { - sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fd, ea_namelist, ea_namelist_size); - } else { - sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size); - } - - if (sizeret == -1 && errno == ERANGE) { - ea_namelist_size *= 2; - } else { - break; - } - } - - if (sizeret == -1) - return NULL; - - DEBUG(10,("get_ea_list: ea_namelist size = %d\n", sizeret )); - - if (sizeret) { - for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) { - struct ea_list *listp, *tmp; - - if (strnequal(p, "system.", 7) || samba_private_attr_name(p)) - continue; - - listp = talloc(mem_ctx, sizeof(struct ea_list)); - if (!listp) - return NULL; - - if (!get_ea_value(mem_ctx, conn, fsp, fname, p, &listp->ea)) { - return NULL; - } - - if (pea_total_len) { - *pea_total_len += 4 + strlen(p) + 1 + listp->ea.value.length; - } - DLIST_ADD_END(ea_list_head, listp, tmp); - } - } - - /* Add on 4 for total length. */ - if (pea_total_len) { - *pea_total_len += 4; - } - return ea_list_head; -} - -/**************************************************************************** - Fill a qfilepathinfo buffer with EA's. -****************************************************************************/ - -static unsigned int fill_ea_buffer(char *pdata, unsigned int total_data_size, - connection_struct *conn, files_struct *fsp, const char *fname) -{ - unsigned int ret_data_size = 4; - char *p = pdata; - size_t total_ea_len; - TALLOC_CTX *mem_ctx = talloc_init("fill_ea_buffer"); - struct ea_list *ea_list = get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len); - - SMB_ASSERT(total_data_size >= 4); - - SIVAL(pdata,0,0); - if (!mem_ctx) { - return 4; - } - - if (!ea_list) { - talloc_destroy(mem_ctx); - return 4; - } - - if (total_ea_len > total_data_size) { - talloc_destroy(mem_ctx); - return 4; - } - - total_data_size -= 4; - for (p = pdata + 4; ea_list; ea_list = ea_list->next) { - size_t dos_namelen; - fstring dos_ea_name; - push_ascii_fstring(dos_ea_name, ea_list->ea.name); - dos_namelen = strlen(dos_ea_name); - if (dos_namelen > 255 || dos_namelen == 0) { - break; - } - if (ea_list->ea.value.length > 65535) { - break; - } - if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) { - break; - } - - /* We know we have room. */ - SCVAL(p,0,ea_list->ea.flags); - SCVAL(p,1,dos_namelen); - SSVAL(p,2,ea_list->ea.value.length); - fstrcpy(p+4, dos_ea_name); - memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length); - - total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length; - p += 4 + dos_namelen + 1 + ea_list->ea.value.length; - } - - ret_data_size = PTR_DIFF(p, pdata); - talloc_destroy(mem_ctx); - SIVAL(pdata,0,ret_data_size); - return ret_data_size; -} - -static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname) -{ - size_t total_ea_len = 0; - TALLOC_CTX *mem_ctx = talloc_init("estimate_ea_size"); - - (void)get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len); - talloc_destroy(mem_ctx); - return total_ea_len; -} - -/**************************************************************************** - Set or delete an extended attribute. -****************************************************************************/ - -static NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, - char *pdata, int total_data) -{ - unsigned int namelen; - unsigned int ealen; - int ret; - fstring unix_ea_name; - - if (!lp_ea_support(SNUM(conn))) { - return NT_STATUS_EAS_NOT_SUPPORTED; - } - - if (total_data < 8) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (IVAL(pdata,0) > total_data) { - DEBUG(10,("set_ea: bad total data size (%u) > %u\n", IVAL(pdata,0), (unsigned int)total_data)); - return NT_STATUS_INVALID_PARAMETER; - } - - pdata += 4; - namelen = CVAL(pdata,1); - ealen = SVAL(pdata,2); - pdata += 4; - if (total_data < 8 + namelen + 1 + ealen) { - DEBUG(10,("set_ea: bad total data size (%u) < 8 + namelen (%u) + 1 + ealen (%u)\n", - (unsigned int)total_data, namelen, ealen)); - return NT_STATUS_INVALID_PARAMETER; - } - - if (pdata[namelen] != '\0') { - DEBUG(10,("set_ea: ea name not null terminated\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */ - pull_ascii(&unix_ea_name[5], pdata, sizeof(fstring) - 5, -1, STR_TERMINATE); - pdata += (namelen + 1); - - DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, ealen)); - if (ealen) { - DEBUG(10,("set_ea: data :\n")); - dump_data(10, pdata, ealen); - } - - if (samba_private_attr_name(unix_ea_name)) { - DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name)); - return NT_STATUS_ACCESS_DENIED; - } - - if (ealen == 0) { - /* Remove the attribute. */ - if (fsp && (fsp->fd != -1)) { - DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n", - unix_ea_name, fsp->fsp_name)); - ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, unix_ea_name); - } else { - DEBUG(10,("set_ea: deleting ea name %s on file %s.\n", - unix_ea_name, fname)); - ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name); - } -#ifdef ENOATTR - /* Removing a non existent attribute always succeeds. */ - DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n", unix_ea_name)); - if (ret == -1 && errno == ENOATTR) { - ret = 0; - } -#endif - } else { - if (fsp && (fsp->fd != -1)) { - DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n", - unix_ea_name, fsp->fsp_name)); - ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, unix_ea_name, pdata, ealen, 0); - } else { - DEBUG(10,("set_ea: setting ea name %s on file %s.\n", - unix_ea_name, fname)); - ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name, pdata, ealen, 0); - } - } - - if (ret == -1) { - if (errno == ENOTSUP) { - return NT_STATUS_EAS_NOT_SUPPORTED; - } - return map_nt_error_from_unix(errno); - } - - return NT_STATUS_OK; -} - -/**************************************************************************** - Send the required number of replies back. - We assume all fields other than the data fields are - 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) -{ - /* 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. -****************************************************************************/ - -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; - int16 open_attr; - BOOL oplock_request; -#if 0 - BOOL return_additional_info; - int16 open_sattr; - time_t open_time; -#endif - int16 open_ofun; - int32 open_size; - char *pname; - pstring fname; - 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; - NTSTATUS status; - - /* - * 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]; - - if (IS_IPC(conn)) - return(ERROR_DOS(ERRSRV,ERRaccess)); - - srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", - fname,open_mode, open_attr, open_ofun, open_size)); - - /* XXXX we need to handle passed times, sattr and flags */ - - unix_convert(fname,conn,0,&bad_path,&sbuf); - - if (!check_name(fname,conn)) { - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - - fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,(uint32)open_attr, - oplock_request, &rmode,&smb_action); - - if (!fsp) { - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); - } - - size = get_file_size(sbuf); - 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); - - 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. -**********************************************************/ - -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 (StrCaseCmp(str,mask) != 0) { - return False; - } - if (ms_has_wild(str)) { - return False; - } - return True; -} - -/**************************************************************************** - 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_ISUID : 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; -} - -/**************************************************************************** - Checks for SMB_TIME_NO_CHANGE and if not found calls interpret_long_date. -****************************************************************************/ - -time_t interpret_long_unix_date(char *p) -{ - DEBUG(1,("interpret_long_unix_date\n")); - if(IVAL(p,0) == SMB_TIME_NO_CHANGE_LO && - IVAL(p,4) == SMB_TIME_NO_CHANGE_HI) { - return -1; - } else { - return interpret_long_date(p); - } -} - -/**************************************************************************** - Get a level dependent lanman2 dir entry. -****************************************************************************/ - -static BOOL get_lanman2_dir_entry(connection_struct *conn, - void *inbuf, void *outbuf, - char *path_mask,int dirtype,int info_level, - int requires_resume_key, - BOOL dont_descend,char **ppdata, - char *base_data, int space_remaining, - BOOL *out_of_space, BOOL *got_exact_match, - int *last_name_off) -{ - const char *dname; - BOOL found = False; - SMB_STRUCT_STAT sbuf; - pstring mask; - pstring pathreal; - pstring fname; - char *p, *q, *pdata = *ppdata; - uint32 reskey=0; - int prev_dirpos=0; - int mode=0; - SMB_OFF_T file_size = 0; - SMB_BIG_UINT 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_m(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 && !mangle_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); - mangle_map( 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 (INFO_LEVEL_IS_UNIX(info_level)) { - if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) { - DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", - pathreal,strerror(errno))); - continue; - } - } else if (SMB_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, - &sbuf)) { - - DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal)); - sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; - - } else { - - DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", - pathreal,strerror(errno))); - continue; - } - } - - 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; - } - - file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(NULL,&sbuf); - 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) - file_size = 0; - - DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname)); - - found = True; - } - } - - mangle_map(fname,False,True,SNUM(conn)); - - p = pdata; - nameptr = p; - - nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL; - - switch (info_level) { - case SMB_INFO_STANDARD: - 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)file_size); - SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size); - SSVAL(p,l1_attrFile,mode); - p += l1_achName; - nameptr = p; - p += align_string(outbuf, p, 0); - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE); - if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) - SCVAL(nameptr, -1, len-2); - else - SCVAL(nameptr, -1, len-1); - p += len; - break; - - case SMB_INFO_QUERY_EA_SIZE: - 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)file_size); - SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size); - SSVAL(p,l2_attrFile,mode); - SIVAL(p,l2_cbList,0); /* No extended attributes */ - p += l2_achName; - nameptr = p; - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN); - if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) - SCVAL(nameptr, -1, len-2); - else - SCVAL(nameptr, -1, len-1); - p += len; - break; - - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - was_8_3 = mangle_is_8_3(fname, True); - 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,file_size); - SOFF_T(p,8,allocation_size); - p += 16; - SIVAL(p,0,nt_extmode); p += 4; - q = p; p += 4; - SIVAL(p,0,0); p += 4; - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - memset(p,'\0',26); - if (!was_8_3 && lp_manglednames(SNUM(conn))) { - pstring mangled_name; - pstrcpy(mangled_name, fname); - mangle_map(mangled_name,True,True,SNUM(conn)); - mangled_name[12] = 0; - len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE); - SSVAL(p, 0, len); - } else { - SSVAL(p,0,0); - *(p+2) = 0; - } - p += 2 + 24; - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); - SIVAL(q,0,len); - p += len; - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - case SMB_FIND_FILE_DIRECTORY_INFO: - 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,file_size); - SOFF_T(p,8,allocation_size); - p += 16; - SIVAL(p,0,nt_extmode); p += 4; - p += 4; - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); - SIVAL(p, -4, len); - p += len; - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - 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,file_size); - SOFF_T(p,8,allocation_size); - p += 16; - SIVAL(p,0,nt_extmode); - p += 4; - - SIVAL(p,4,0); /* ea size */ - len = srvstr_push(outbuf, p+8, fname, -1, STR_TERMINATE_ASCII); - SIVAL(p, 0, len); - p += 8 + len; - - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - case SMB_FIND_FILE_NAMES_INFO: - p += 4; - SIVAL(p,0,reskey); p += 4; - p += 4; - /* this must *not* be null terminated or w2k gets in a loop trying to set an - acl on a dir (tridge) */ - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); - SIVAL(p, -4, len); - p += len; - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - case SMB_FIND_FILE_LEVEL_261: - 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,file_size); - SOFF_T(p,8,allocation_size); - p += 16; - SIVAL(p,0,nt_extmode); - p += 4; - len = srvstr_push(outbuf, p + 20, fname, -1, STR_TERMINATE_ASCII); - SIVAL(p, 0, len); - memset(p+4,'\0',16); /* EA size. Unknown 0 1 2 */ - p += 20 + len; /* Strlen, EA size. Unknown 0 1 2, string itself */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - case SMB_FIND_FILE_LEVEL_262: - was_8_3 = mangle_is_8_3(fname, True); - 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,file_size); - SOFF_T(p,8,allocation_size); - p += 16; - SIVAL(p,0,nt_extmode); p += 4; - q = p; p += 4; - SIVAL(p,0,0); p += 4; - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - memset(p,'\0',26); - if (!was_8_3 && lp_manglednames(SNUM(conn))) { - pstring mangled_name; - pstrcpy(mangled_name, fname); - mangle_map(mangled_name,True,True,SNUM(conn)); - mangled_name[12] = 0; - len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE); - SSVAL(p, 0, len); - } else { - SSVAL(p,0,0); - *(p+2) = 0; - } - p += 2 + 24; - memset(p, '\0', 10); /* 2 4 byte unknowns plus a zero reserved. */ - p += 10; - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); - SIVAL(q,0,len); - p += len; - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - /* CIFS UNIX Extension. */ - - case SMB_FIND_FILE_UNIX: - p+= 4; - SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ - - /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ - SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */ - p+= 8; - - SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */ - 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; - - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE); - p += len; - - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */ - p = pdata + len; - /* End of SMB_QUERY_FILE_UNIX_BASIC */ - - 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, 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; - NTSTATUS ntstatus = NT_STATUS_OK; - - if (total_params < 12) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - *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)); - - switch (info_level) { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - 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: - case SMB_FIND_FILE_LEVEL_261: - case SMB_FIND_FILE_LEVEL_262: - break; - case SMB_FIND_FILE_UNIX: - if (!lp_unix_extensions()) - return(ERROR_DOS(ERRDOS,ERRunknownlevel)); - break; - default: - return(ERROR_DOS(ERRDOS,ERRunknownlevel)); - } - - srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus); - if (!NT_STATUS_IS_OK(ntstatus)) { - return ERROR_NT(ntstatus); - } - - RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); - - unix_convert(directory,conn,0,&bad_path,&sbuf); - if(!check_name(directory,conn)) { - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - - p = strrchr_m(directory,'/'); - if(p == NULL) { - /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */ - if((directory[0] == '.') && (directory[1] == '\0')) - pstrcpy(mask,"*"); - else - 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; - - 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, - inbuf, outbuf, - 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_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(!mangle_is_8_3_wildcards( mask, False)) - mangle_map(mask, True, True, SNUM(conn)); - - return(-1); -} - -/**************************************************************************** - Reply to a TRANS2_FINDNEXT. -****************************************************************************/ - -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; - NTSTATUS ntstatus = NT_STATUS_OK; - - if (total_params < 12) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - *mask = *directory = *resume_name = 0; - - srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus); - if (!NT_STATUS_IS_OK(ntstatus)) { - return ERROR_NT(ntstatus); - } - - 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 SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - 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; - const char *dname = NULL; - pstring dname_pstring; - 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); - if (dname) { - /* - * Remember, mangle_map is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - /* make sure we get a copy that mangle_map can modify */ - - pstrcpy(dname_pstring, dname); - mangle_map( dname_pstring, False, True, SNUM(conn)); - - if(strcsequal( resume_name, dname_pstring)) { - 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, mangle_map is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname) { - /* make sure we get a copy that mangle_map can modify */ - - pstrcpy(dname_pstring, dname); - mangle_map(dname_pstring, False, True, SNUM(conn)); - - if(strcsequal( resume_name, dname_pstring)) { - 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, - inbuf, outbuf, - 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 */ - } - - /* 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)); - - 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 ) ); - - return(-1); -} - -/**************************************************************************** - 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, 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, len; - SMB_STRUCT_STAT st; - char *vname = volume_label(SNUM(conn)); - int snum = SNUM(conn); - char *fstype = lp_fstype(SNUM(conn)); - int quota_flag = 0; - - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - - if(SMB_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 SMB_INFO_ALLOCATION: - { - SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; - data_len = 18; - SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); - block_size = lp_block_size(snum); - if (bsize < block_size) { - SMB_BIG_UINT factor = block_size/bsize; - bsize = block_size; - dsize /= factor; - dfree /= factor; - } - if (bsize > block_size) { - SMB_BIG_UINT factor = bsize/block_size; - bsize = block_size; - dsize *= factor; - dfree *= factor; - } - bytes_per_sector = 512; - sectors_per_unit = bsize/bytes_per_sector; - - DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ -cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit, - (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); - - SIVAL(pdata,l1_idFileSystem,st.st_dev); - SIVAL(pdata,l1_cSectorUnit,sectors_per_unit); - SIVAL(pdata,l1_cUnit,dsize); - SIVAL(pdata,l1_cUnitAvail,dfree); - SSVAL(pdata,l1_cbSector,bytes_per_sector); - break; - } - - case SMB_INFO_VOLUME: - /* Return volume name */ - /* - * 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) ); - len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_NOALIGN); - SCVAL(pdata,l2_vol_cch,len); - data_len = l2_vol_szVolLabel + len; - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", - (unsigned)st.st_ctime, len, vname)); - break; - - case SMB_QUERY_FS_ATTRIBUTE_INFO: - case SMB_FS_ATTRIBUTE_INFORMATION: - - -#if defined(HAVE_SYS_QUOTAS) - quota_flag = FILE_VOLUME_QUOTAS; -#endif - - SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| - (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)| - quota_flag); /* FS ATTRIBUTES */ - - 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 */ - len = srvstr_push(outbuf, pdata+12, fstype, -1, STR_UNICODE); - SIVAL(pdata,8,len); - data_len = 12 + len; - break; - - case SMB_QUERY_FS_LABEL_INFO: - case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(outbuf, pdata+4, vname, -1, 0); - data_len = 4 + len; - SIVAL(pdata,0,len); - 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)); - - len = srvstr_push(outbuf, pdata+18, vname, -1, STR_UNICODE); - SIVAL(pdata,12,len); - data_len = 18+len; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", - (int)strlen(vname),vname, lp_servicename(snum))); - break; - - case SMB_QUERY_FS_SIZE_INFO: - case SMB_FS_SIZE_INFORMATION: - { - SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; - data_len = 24; - SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); - block_size = lp_block_size(snum); - if (bsize < block_size) { - SMB_BIG_UINT factor = block_size/bsize; - bsize = block_size; - dsize /= factor; - dfree /= factor; - } - if (bsize > block_size) { - SMB_BIG_UINT factor = bsize/block_size; - bsize = block_size; - dsize *= factor; - dfree *= factor; - } - bytes_per_sector = 512; - sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ -cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, - (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); - SBIG_UINT(pdata,0,dsize); - SBIG_UINT(pdata,8,dfree); - SIVAL(pdata,16,sectors_per_unit); - SIVAL(pdata,20,bytes_per_sector); - break; - } - - case SMB_FS_FULL_SIZE_INFORMATION: - { - SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; - data_len = 32; - SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); - block_size = lp_block_size(snum); - if (bsize < block_size) { - SMB_BIG_UINT factor = block_size/bsize; - bsize = block_size; - dsize /= factor; - dfree /= factor; - } - if (bsize > block_size) { - SMB_BIG_UINT factor = bsize/block_size; - bsize = block_size; - dsize *= factor; - dfree *= factor; - } - bytes_per_sector = 512; - sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ -cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, - (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); - SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */ - SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */ - SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */ - SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */ - SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */ - 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; - -#ifdef HAVE_SYS_QUOTAS - case SMB_FS_QUOTA_INFORMATION: - /* - * what we have to send --metze: - * - * Unknown1: 24 NULL bytes - * Soft Quota Treshold: 8 bytes seems like SMB_BIG_UINT or so - * Hard Quota Limit: 8 bytes seems like SMB_BIG_UINT or so - * Quota Flags: 2 byte : - * Unknown3: 6 NULL bytes - * - * 48 bytes total - * - * details for Quota Flags: - * - * 0x0020 Log Limit: log if the user exceeds his Hard Quota - * 0x0010 Log Warn: log if the user exceeds his Soft Quota - * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota - * 0x0001 Enable Quotas: enable quota for this fs - * - */ - { - /* we need to fake up a fsp here, - * because its not send in this call - */ - files_struct fsp; - SMB_NTQUOTA_STRUCT quotas; - - ZERO_STRUCT(fsp); - ZERO_STRUCT(quotas); - - fsp.conn = conn; - fsp.fnum = -1; - fsp.fd = -1; - - /* access check */ - if (conn->admin_user != True) { - DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", - lp_servicename(SNUM(conn)),conn->user)); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { - DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - return ERROR_DOS(ERRSRV,ERRerror); - } - - data_len = 48; - - DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn)))); - - /* Unknown1 24 NULL bytes*/ - SBIG_UINT(pdata,0,(SMB_BIG_UINT)0); - SBIG_UINT(pdata,8,(SMB_BIG_UINT)0); - SBIG_UINT(pdata,16,(SMB_BIG_UINT)0); - - /* Default Soft Quota 8 bytes */ - SBIG_UINT(pdata,24,quotas.softlim); - - /* Default Hard Quota 8 bytes */ - SBIG_UINT(pdata,32,quotas.hardlim); - - /* Quota flag 2 bytes */ - SSVAL(pdata,40,quotas.qflags); - - /* Unknown3 6 NULL bytes */ - SSVAL(pdata,42,0); - SIVAL(pdata,44,0); - - break; - } -#endif /* HAVE_SYS_QUOTAS */ - 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; -} - -#ifdef HAVE_SYS_QUOTAS -/**************************************************************************** - 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, int total_params, char **ppdata, int total_data) -{ - char *pdata = *ppdata; - char *params = *pparams; - files_struct *fsp = NULL; - uint16 info_level; - int outsize; - SMB_NTQUOTA_STRUCT quotas; - - ZERO_STRUCT(quotas); - - DEBUG(10,("call_trans2setfsinfo: SET_FS_QUOTA: for service [%s]\n",lp_servicename(SNUM(conn)))); - - /* access check */ - if ((conn->admin_user != True)||!CAN_WRITE(conn)) { - DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", - lp_servicename(SNUM(conn)),conn->user)); - return ERROR_DOS(ERRSRV,ERRaccess); - } - - /* */ - if (total_params < 4) { - DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n", - total_params)); - return ERROR_DOS(ERRDOS,ERRinvalidparam); - } - - fsp = file_fsp(params,0); - - if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { - DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); - return ERROR_NT(NT_STATUS_INVALID_HANDLE); - } - - info_level = SVAL(params,2); - - switch(info_level) { - case SMB_FS_QUOTA_INFORMATION: - /* note: normaly there're 48 bytes, - * but we didn't use the last 6 bytes for now - * --metze - */ - if (total_data < 42) { - DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n", - total_data)); - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - /* unknown_1 24 NULL bytes in pdata*/ - - /* the soft quotas 8 bytes (SMB_BIG_UINT)*/ - quotas.softlim = (SMB_BIG_UINT)IVAL(pdata,24); -#ifdef LARGE_SMB_OFF_T - quotas.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32); -#else /* LARGE_SMB_OFF_T */ - if ((IVAL(pdata,28) != 0)&& - ((quotas.softlim != 0xFFFFFFFF)|| - (IVAL(pdata,28)!=0xFFFFFFFF))) { - /* more than 32 bits? */ - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } -#endif /* LARGE_SMB_OFF_T */ - - /* the hard quotas 8 bytes (SMB_BIG_UINT)*/ - quotas.hardlim = (SMB_BIG_UINT)IVAL(pdata,32); -#ifdef LARGE_SMB_OFF_T - quotas.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32); -#else /* LARGE_SMB_OFF_T */ - if ((IVAL(pdata,36) != 0)&& - ((quotas.hardlim != 0xFFFFFFFF)|| - (IVAL(pdata,36)!=0xFFFFFFFF))) { - /* more than 32 bits? */ - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } -#endif /* LARGE_SMB_OFF_T */ - - /* quota_flags 2 bytes **/ - quotas.qflags = SVAL(pdata,40); - - /* unknown_2 6 NULL bytes follow*/ - - /* now set the quotas */ - if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { - DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - return ERROR_DOS(ERRSRV,ERRerror); - } - - break; - default: - DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n", - info_level)); - return ERROR_DOS(ERRDOS,ERRunknownlevel); - break; - } - - /* - * sending this reply works fine, - * but I'm not sure it's the same - * like windows do... - * --metze - */ - outsize = set_message(outbuf,10,0,True); - - return outsize; -} -#endif /* HAVE_SYS_QUOTAS */ - -/**************************************************************************** - * Utility function to set bad path error. - ****************************************************************************/ - -int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code) -{ - DEBUG(10,("set_bad_path_error: err = %d bad_path = %d\n", - err, (int)bad_path )); - - if(err == ENOENT) { - if (bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } else { - return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND); - } - } - return UNIXERROR(def_class,def_code); -} - -/**************************************************************************** - Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by - file name or file id). -****************************************************************************/ - -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; - char *pdata = *ppdata; - uint16 tran_call = SVAL(inbuf, smb_setup0); - uint16 info_level; - int mode=0; - SMB_OFF_T file_size=0; - SMB_BIG_UINT allocation_size=0; - unsigned int data_size; - unsigned int param_size = 2; - SMB_STRUCT_STAT sbuf; - pstring fname, dos_fname; - char *fullpathname; - char *base_name; - char *p; - SMB_OFF_T pos = 0; - BOOL bad_path = False; - BOOL delete_pending = False; - int len; - time_t c_time; - files_struct *fsp = NULL; - uint32 desired_access = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */ - - if (!params) - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - - if (tran_call == TRANSACT2_QFILEINFO) { - 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)); - - if(fsp && (fsp->fake_file_handle)) { - /* - * This is actually for the QUOTA_FAKE_FILE --metze - */ - - pstrcpy(fname, fsp->fsp_name); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - - } else if(fsp && (fsp->is_directory || fsp->fd == -1)) { - /* - * This is actually a QFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - pstrcpy(fname, fsp->fsp_name); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - - delete_pending = fsp->directory_delete_on_close; - } else { - /* - * Original code - this is an open file. - */ - CHECK_FSP(fsp,conn); - - pstrcpy(fname, fsp->fsp_name); - if (SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); - return(UNIXERROR(ERRDOS,ERRbadfid)); - } - pos = fsp->position_information; - delete_pending = fsp->delete_on_close; - desired_access = fsp->desired_access; - } - } else { - NTSTATUS status = NT_STATUS_OK; - - /* 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)); - - srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - } - - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) - return ERROR_DOS(ERRDOS,ERRunknownlevel); - - DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n", - fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); - - p = strrchr_m(fname,'/'); - if (!p) - base_name = fname; - else - base_name = p+1; - - mode = dos_mode(conn,fname,&sbuf); - if (!mode) - mode = FILE_ATTRIBUTE_NORMAL; - - fullpathname = fname; - file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(fsp,&sbuf); - if (mode & aDIR) - file_size = 0; - - params = Realloc(*pparams,2); - if (params == NULL) - 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_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_DOS(ERRDOS,ERReasnotsupported); - } - - memset((char *)pdata,'\0',data_size); - - c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); - - if (lp_dos_filetime_resolution(SNUM(conn))) { - c_time &= ~1; - sbuf.st_atime &= ~1; - sbuf.st_mtime &= ~1; - sbuf.st_mtime &= ~1; - } - - /* NT expects the name to be in an exact form of the *full* - filename. See the trans2 torture test */ - if (strequal(base_name,".")) { - pstrcpy(dos_fname, "\\"); - } else { - pstr_sprintf(dos_fname, "\\%s", fname); - string_replace(dos_fname, '/', '\\'); - } - - switch (info_level) { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - data_size = (info_level==1?22:26); - put_dos_date2(pdata,l1_fdateCreation,c_time); - 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)file_size); - SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); - SSVAL(pdata,l1_attrFile,mode); - SIVAL(pdata,l1_attrFile+2,0); /* this is what win2003 does */ - break; - - case SMB_INFO_IS_NAME_VALID: - if (tran_call == TRANSACT2_QFILEINFO) { - /* os/2 needs this ? really ?*/ - return ERROR_DOS(ERRDOS,ERRbadfunc); - } - data_size = 0; - param_size = 0; - break; - - case SMB_INFO_QUERY_EAS_FROM_LIST: - data_size = 24; - put_dos_date2(pdata,0,c_time); - put_dos_date2(pdata,4,sbuf.st_atime); - put_dos_date2(pdata,8,sbuf.st_mtime); - SIVAL(pdata,12,(uint32)file_size); - SIVAL(pdata,16,(uint32)allocation_size); - SIVAL(pdata,20,mode); - break; - - case SMB_INFO_QUERY_ALL_EAS: - /* We have data_size bytes to put EA's into. */ - data_size = fill_ea_buffer(pdata, data_size, conn, fsp, fname); - break; - - case SMB_FILE_BASIC_INFORMATION: - case SMB_QUERY_FILE_BASIC_INFO: - - if (info_level == SMB_QUERY_FILE_BASIC_INFO) - data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */ - else { - data_size = 40; - SIVAL(pdata,36,0); - } - put_long_date(pdata,c_time); - 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 */ - SIVAL(pdata,32,mode); - - DEBUG(5,("SMB_QFBI - ")); - { - time_t create_time = c_time; - DEBUG(5,("create: %s ", ctime(&create_time))); - } - DEBUG(5,("access: %s ", ctime(&sbuf.st_atime))); - DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime))); - DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime))); - DEBUG(5,("mode: %x\n", mode)); - - break; - - case SMB_FILE_STANDARD_INFORMATION: - case SMB_QUERY_FILE_STANDARD_INFO: - - data_size = 24; - SOFF_T(pdata,0,allocation_size); - SOFF_T(pdata,8,file_size); - if (delete_pending & sbuf.st_nlink) - SIVAL(pdata,16,sbuf.st_nlink - 1); - else - SIVAL(pdata,16,sbuf.st_nlink); - SCVAL(pdata,20,0); - SCVAL(pdata,21,(mode&aDIR)?1:0); - break; - - case SMB_FILE_EA_INFORMATION: - case SMB_QUERY_FILE_EA_INFO: - { - unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - data_size = 4; - SIVAL(pdata,0,ea_size); - break; - } - - /* Get the 8.3 name - used if NT SMB was negotiated. */ - case SMB_QUERY_FILE_ALT_NAME_INFO: - case SMB_FILE_ALTERNATE_NAME_INFORMATION: - { - pstring short_name; - - pstrcpy(short_name,base_name); - /* Mangle if not already 8.3 */ - if(!mangle_is_8_3(short_name, True)) { - mangle_map(short_name,True,True,SNUM(conn)); - } - len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_UNICODE); - data_size = 4 + len; - SIVAL(pdata,0,len); - break; - } - - case SMB_QUERY_FILE_NAME_INFO: - /* - this must be *exactly* right for ACLs on mapped drives to work - */ - len = srvstr_push(outbuf, pdata+4, dos_fname, -1, STR_UNICODE); - data_size = 4 + len; - SIVAL(pdata,0,len); - break; - - case SMB_FILE_ALLOCATION_INFORMATION: - case SMB_QUERY_FILE_ALLOCATION_INFO: - data_size = 8; - SOFF_T(pdata,0,allocation_size); - break; - - case SMB_FILE_END_OF_FILE_INFORMATION: - case SMB_QUERY_FILE_END_OF_FILEINFO: - data_size = 8; - SOFF_T(pdata,0,file_size); - break; - - case SMB_QUERY_FILE_ALL_INFO: - case SMB_FILE_ALL_INFORMATION: - put_long_date(pdata,c_time); - 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 */ - SIVAL(pdata,32,mode); - pdata += 40; - SOFF_T(pdata,0,allocation_size); - SOFF_T(pdata,8,file_size); - if (delete_pending && sbuf.st_nlink) - SIVAL(pdata,16,sbuf.st_nlink - 1); - else - SIVAL(pdata,16,sbuf.st_nlink); - SCVAL(pdata,20,delete_pending); - SCVAL(pdata,21,(mode&aDIR)?1:0); - pdata += 24; - pdata += 4; /* EA info */ - len = srvstr_push(outbuf, pdata+4, dos_fname, -1, STR_UNICODE); - SIVAL(pdata,0,len); - pdata += 4 + len; - data_size = PTR_DIFF(pdata,(*ppdata)); - break; - - case SMB_FILE_INTERNAL_INFORMATION: - /* This should be an index number - looks like - dev/ino to me :-) - - I think this causes us to fail the IFSKIT - BasicFileInformationTest. -tpot */ - - SIVAL(pdata,0,sbuf.st_dev); - SIVAL(pdata,4,sbuf.st_ino); - data_size = 8; - break; - - case SMB_FILE_ACCESS_INFORMATION: - SIVAL(pdata,0,desired_access); - data_size = 4; - break; - - case SMB_FILE_NAME_INFORMATION: - /* Pathname with leading '\'. */ - { - size_t byte_len; - byte_len = dos_PutUniCode(pdata+4,dos_fname,max_data_bytes,False); - SIVAL(pdata,0,byte_len); - data_size = 4 + byte_len; - break; - } - - case SMB_FILE_DISPOSITION_INFORMATION: - data_size = 1; - SCVAL(pdata,0,delete_pending); - break; - - case SMB_FILE_POSITION_INFORMATION: - data_size = 8; - SOFF_T(pdata,0,pos); - break; - - case SMB_FILE_MODE_INFORMATION: - SIVAL(pdata,0,mode); - data_size = 4; - break; - - case SMB_FILE_ALIGNMENT_INFORMATION: - SIVAL(pdata,0,0); /* No alignment needed. */ - data_size = 4; - break; - -#if 0 - /* - * 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: -#endif - case SMB_FILE_STREAM_INFORMATION: - if (mode & aDIR) { - data_size = 0; - } else { - size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False); - SIVAL(pdata,0,0); /* ??? */ - SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */ - SOFF_T(pdata,8,file_size); - SIVAL(pdata,16,allocation_size); - SIVAL(pdata,20,0); /* ??? */ - data_size = 24 + byte_len; - } - break; - - case SMB_QUERY_COMPRESSION_INFO: - case SMB_FILE_COMPRESSION_INFORMATION: - SOFF_T(pdata,0,file_size); - SIVAL(pdata,8,0); /* ??? */ - SIVAL(pdata,12,0); /* ??? */ - data_size = 16; - break; - - case SMB_FILE_NETWORK_OPEN_INFORMATION: - put_long_date(pdata,c_time); - 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 */ - SIVAL(pdata,32,allocation_size); - SOFF_T(pdata,40,file_size); - SIVAL(pdata,48,mode); - SIVAL(pdata,52,0); /* ??? */ - data_size = 56; - break; - - case SMB_FILE_ATTRIBUTE_TAG_INFORMATION: - SIVAL(pdata,0,mode); - SIVAL(pdata,4,0); - data_size = 8; - break; - - /* - * 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,get_file_size(sbuf)); /* File size 64 Bit */ - pdata += 8; - - SOFF_T(pdata,0,get_allocation_size(fsp,&sbuf)); /* Number of bytes used on disk - 64 Bit */ - 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; - -#ifdef S_ISLNK - if(!S_ISLNK(sbuf.st_mode)) - return(UNIXERROR(ERRSRV,ERRbadlink)); -#else - return(UNIXERROR(ERRDOS,ERRbadlink)); -#endif - len = SMB_VFS_READLINK(conn,fullpathname, buffer, sizeof(pstring)-1); /* read link */ - if (len == -1) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - buffer[len] = 0; - len = srvstr_push(outbuf, pdata, buffer, -1, STR_TERMINATE); - pdata += len; - data_size = PTR_DIFF(pdata,(*ppdata)); - - break; - } - - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size); - - return(-1); -} - -/**************************************************************************** - 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. -****************************************************************************/ - -NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close) -{ - /* - * Only allow delete on close for writable shares. - */ - - 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 && !(fsp->desired_access & DELETE_ACCESS)) { - 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 { - 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; -} - -/**************************************************************************** - Sets the delete on close flag over all share modes on this file. - 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. -****************************************************************************/ - -NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close) -{ - DEBUG(10,("set_delete_on_close_over_all: %s delete on close flag for fnum = %d, file %s\n", - delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name )); - - if (fsp->is_directory || fsp->is_stat) - return NT_STATUS_OK; - - 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; - } - - unlock_share_entry_fsp(fsp); - 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 - fstring last_component; - pstring link_dest; - pstring link_test; - char *p; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - - pstrcpy(link_dest, link_dest_in); - unix_convert(link_dest,conn,0,&bad_path,&sbuf); - - /* Store the UNIX converted path. */ - pstrcpy(link_dest_out, link_dest); - - p = strrchr(link_dest, '/'); - if (p) { - fstrcpy(last_component, p+1); - *p = '\0'; - } else { - fstrcpy(last_component, link_dest); - pstrcpy(link_dest, "./"); - } - - if (SMB_VFS_REALPATH(conn,link_dest,resolved_name) == NULL) - return -1; - - pstrcpy(link_dest, resolved_name); - pstrcat(link_dest, "/"); - pstrcat(link_dest, last_component); - - if (*link_dest != '/') { - /* Relative path. */ - pstrcpy(link_test, conn->connectpath); - pstrcat(link_test, "/"); - pstrcat(link_test, link_dest); - } else { - pstrcpy(link_test, link_dest); - } - - /* - * Check if the link is within the share. - */ - - if (strncmp(conn->connectpath, link_test, strlen(conn->connectpath))) { - errno = EACCES; - return -1; - } - return 0; -} - -/**************************************************************************** - Set a hard link (called by UNIX extensions and by NT rename with HARD link - code. -****************************************************************************/ - -NTSTATUS hardlink_internals(connection_struct *conn, char *name, char *newname) -{ - BOOL bad_path_src = False; - BOOL bad_path_dest = False; - SMB_STRUCT_STAT sbuf1, sbuf2; - BOOL rc, rcdest; - pstring last_component_src; - pstring last_component_dest; - NTSTATUS status = NT_STATUS_OK; - - ZERO_STRUCT(sbuf1); - ZERO_STRUCT(sbuf2); - - /* No wildcards. */ - if (ms_has_wild(name) || ms_has_wild(newname)) { - return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - } - - rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1); - if (!rc && bad_path_src) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_src[0] == '.') { - if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - } - - /* source must already exist. */ - if (!VALID_STAT(sbuf1)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2); - if (!rcdest && bad_path_dest) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_dest[0] == '.') { - if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - } - - /* Disallow if already exists. */ - if (VALID_STAT(sbuf2)) { - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - /* No links from a directory. */ - if (S_ISDIR(sbuf1.st_mode)) { - return NT_STATUS_FILE_IS_A_DIRECTORY; - } - - if (ensure_link_is_safe(conn, newname, newname) != 0) - return NT_STATUS_ACCESS_DENIED; - - DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", name, newname )); - - if (SMB_VFS_LINK(conn,name,newname) != 0) { - status = map_nt_error_from_unix(errno); - DEBUG(3,("hardlink_internals: Error %s link %s -> %s\n", - nt_errstr(status), name,newname)); - } - - return status; -} - -/**************************************************************************** - 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 fname; - 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; - NTSTATUS status = NT_STATUS_OK; - - if (!params) - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - - 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->fd == -1)) { - /* - * This is actually a SETFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - pstrcpy(fname, fsp->fsp_name); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { - DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, 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) && 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 - return (UNIXERROR(ERRDOS,ERRbadpath)); - } else { - /* - * Original code - this is an open file. - */ - CHECK_FSP(fsp,conn); - - pstrcpy(fname, fsp->fsp_name); - fd = fsp->fd; - - if (SMB_VFS_FSTAT(fsp,fd,&sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: 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); - srvstr_get_path(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - unix_convert(fname,conn,0,&bad_path,&sbuf); - - /* - * For CIFS UNIX extensions the target name may not exist. - */ - - if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) { - DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } - - if(!check_name(fname, conn)) { - return set_bad_path_error(errno, bad_path, outbuf, 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 (fnum %d) info_level=%d totdata=%d\n", - tran_call,fname, fsp ? fsp->fnum : -1, 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); - - if (fsp) { - /* the pending modtime overrides the current modtime */ - sbuf.st_mtime = fsp->pending_modtime; - } - - size = get_file_size(sbuf); - 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; - - switch (info_level) { - case SMB_INFO_STANDARD: - { - if (total_data < 12) - 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); - break; - } - - case SMB_INFO_SET_EA: - status = set_ea(conn, fsp, fname, pdata, total_data); - if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) - return ERROR_NT(status); - 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); - - if (write_time > tvs.modtime && write_time != 0xffffffff) { - tvs.modtime = write_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_BIG_UINT allocation_size; - - if (total_data < 8) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - allocation_size = (SMB_BIG_UINT)IVAL(pdata,0); -#ifdef LARGE_SMB_OFF_T - allocation_size |= (((SMB_BIG_UINT)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 */ - DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", - fname, (double)allocation_size )); - - if (allocation_size) - allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); - - if(allocation_size != get_file_size(sbuf)) { - SMB_STRUCT_STAT new_sbuf; - - 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(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_shared1(conn, fname, &sbuf,FILE_WRITE_DATA, - SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, - 0, &access_mode, &action); - - if (new_fsp == NULL) - return(UNIXERROR(ERRDOS,ERRbadpath)); - ret = vfs_allocate_file_space(new_fsp, allocation_size); - if (SMB_VFS_FSTAT(new_fsp,new_fsp->fd,&new_sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: 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 (SMB_VFS_FSTAT(fsp,fd,&new_sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - ret = -1; - } - } - if (ret == -1) - return ERROR_NT(NT_STATUS_DISK_FULL); - - /* Allocate can truncate size... */ - size = get_file_size(new_sbuf); - } - - 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); -#else /* LARGE_SMB_OFF_T */ - 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; - } - - case SMB_FILE_DISPOSITION_INFORMATION: - case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */ - { - BOOL delete_on_close; - - if (total_data < 1) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - delete_on_close = (CVAL(pdata,0) ? True : False); - - /* Just ignore this set on a path. */ - if (tran_call != TRANSACT2_SETFILEINFO) - break; - - if (fsp == NULL) - return(UNIXERROR(ERRDOS,ERRbadfid)); - - status = set_delete_on_close_internal(fsp, delete_on_close); - - if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) - return ERROR_NT(status); - - /* The set is across all open files on this dev/inode pair. */ - status =set_delete_on_close_over_all(fsp, delete_on_close); - if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) - return ERROR_NT(status); - - break; - } - - case SMB_FILE_POSITION_INFORMATION: - { - SMB_BIG_UINT position_information; - - if (total_data < 8) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - position_information = (SMB_BIG_UINT)IVAL(pdata,0); -#ifdef LARGE_SMB_OFF_T - position_information |= (((SMB_BIG_UINT)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 */ - DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n", - fname, (double)position_information )); - if (fsp) - fsp->position_information = position_information; - break; - } - - /* - * CIFS UNIX extensions. - */ - - case SMB_SET_FILE_UNIX_BASIC: - { - uint32 raw_unixmode; - - if (total_data < 100) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO && - IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) { - 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_unix_date(pdata); /* access_time */ - tvs.modtime = interpret_long_unix_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 (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - inherit_access_acl(conn, fname, unixmode); - - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); -#endif /* HAVE_MAKEDEV_FN */ - - } - - /* - * Deal with the UNIX specific mode set. - */ - - if (raw_unixmode != SMB_MODE_NO_CHANGE) { - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", - (unsigned int)unixmode, fname )); - if (SMB_VFS_CHMOD(conn,fname,unixmode) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* - * Deal with the UNIX specific uid set. - */ - - 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 (SMB_VFS_CHOWN(conn,fname,set_owner, (gid_t)-1) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* - * Deal with the UNIX specific gid set. - */ - - 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 (SMB_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)); - - srvstr_get_path(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", - fname, link_dest )); - - if (SMB_VFS_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); - } - - case SMB_SET_FILE_UNIX_HLINK: - { - pstring link_dest; - - /* Set a hard link. */ - srvstr_get_path(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", - fname, link_dest )); - - status = hardlink_internals(conn, fname, link_dest); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); - } - - case SMB_FILE_RENAME_INFORMATION: - { - BOOL overwrite; - uint32 root_fid; - uint32 len; - pstring newname; - pstring base_name; - char *p; - - if (total_data < 12) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - overwrite = (CVAL(pdata,0) ? True : False); - root_fid = IVAL(pdata,4); - len = IVAL(pdata,8); - srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - /* Check the new name has no '/' characters. */ - if (strchr_m(newname, '/')) - return ERROR_NT(NT_STATUS_NOT_SUPPORTED); - - RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); - - /* Create the base directory. */ - pstrcpy(base_name, fname); - p = strrchr_m(base_name, '/'); - if (p) - *p = '\0'; - /* Append the new name. */ - pstrcat(base_name, "/"); - pstrcat(base_name, newname); - - if (fsp) { - DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", - fsp->fnum, fsp->fsp_name, base_name )); - status = rename_internals_fsp(conn, fsp, base_name, overwrite); - } else { - DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n", - fname, newname )); - status = rename_internals(conn, fname, base_name, 0, overwrite); - } - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - process_pending_change_notify_queue((time_t)0); - SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); - } - default: - return ERROR_DOS(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)); - - if (dosmode) { - if (S_ISDIR(sbuf.st_mode)) - dosmode |= aDIR; - else - dosmode &= ~aDIR; - } - - 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 = get_file_size(sbuf); - } - - /* - * 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 close. 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_set_dosmode(conn, fname, dosmode, NULL)) { - DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno))); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - } - - if (size != get_file_size(sbuf)) { - - int ret; - - 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), - FILE_ATTRIBUTE_NORMAL, - 0, &access_mode, &action); - - if (new_fsp == NULL) - return(UNIXERROR(ERRDOS,ERRbadpath)); - ret = vfs_set_filelen(new_fsp, size); - close_file(new_fsp,True); - } else { - ret = vfs_set_filelen(fsp, size); - } - - if (ret == -1) - return (UNIXERROR(ERRHRD,ERRdiskfull)); - } - - 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). -****************************************************************************/ - -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; - NTSTATUS status = NT_STATUS_OK; - - if (!CAN_WRITE(conn)) - return ERROR_DOS(ERRSRV,ERRaccess); - - if (total_params < 4) - return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - - srvstr_get_path(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } - - 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)); - - if(ret < 0) { - DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - return set_bad_path_error(errno, bad_path, outbuf, 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); -} - -/**************************************************************************** - 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, int total_params, char **ppdata, int total_data) -{ - 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); -} - -/**************************************************************************** - 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, int total_params, char **ppdata, int total_data) -{ - char *params = *pparams; - - DEBUG(3,("call_trans2findnotifynext\n")); - - /* 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 */ - - send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); - - return(-1); -} - -/**************************************************************************** - 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, int total_params, char **ppdata, int total_data) -{ - char *params = *pparams; - 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); - - srvstr_pull(inbuf, pathname, ¶ms[2], sizeof(pathname), -1, STR_TERMINATE); - if((reply_size = setup_dfs_referral(conn, pathname,max_referral_level,ppdata)) < 0) - return UNIXERROR(ERRDOS,ERRbadfile); - - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); - send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); - - return(-1); -} - -#define LMCAT_SPL 0x53 -#define LMFUNC_GETJOBID 0x60 - -/**************************************************************************** - 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, int total_params, char **ppdata, int total_data) -{ - char *pdata = *ppdata; - files_struct *fsp = file_fsp(inbuf,smb_vwv15); - - /* check for an invalid fid before proceeding */ - - if (!fsp) - return(ERROR_DOS(ERRDOS,ERRbadfid)); - - 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; - - /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2 - CAN ACCEPT THIS IN UNICODE. JRA. */ - - SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */ - srvstr_push( outbuf, pdata + 2, global_myname(), 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ - srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* 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 outsize = 0; - int dptr_num=SVALS(inbuf,smb_vwv0); - START_PROFILE(SMBfindclose); - - DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num)); - - dptr_close(&dptr_num); - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num)); - - END_PROFILE(SMBfindclose); - return(outsize); -} - -/**************************************************************************** - Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search). -****************************************************************************/ - -int reply_findnclose(connection_struct *conn, - char *inbuf,char *outbuf,int length,int bufsize) -{ - int outsize = 0; - int dptr_num= -1; - START_PROFILE(SMBfindnclose); - - dptr_num = SVAL(inbuf,smb_vwv0); - - DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num)); - - /* We never give out valid handles for a - findnotifyfirst - so any dptr_num is ok here. - Just ignore it. */ - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num)); - - END_PROFILE(SMBfindnclose); - return(outsize); -} - -/**************************************************************************** - Reply to a SMBtranss2 - just ignore it! -****************************************************************************/ - -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)); - END_PROFILE(SMBtranss2); - return(-1); -} - -/**************************************************************************** - Reply to a SMBtrans2. -****************************************************************************/ - -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); - unsigned int total_data =SVAL(inbuf, smb_tdscnt); -#if 0 - unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt); - unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt); - unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt); - BOOL close_tid = BITSETW(inbuf+smb_flags,0); - BOOL no_final_response = BITSETW(inbuf+smb_flags,1); - int32 timeout = IVALS(inbuf,smb_timeout); -#endif - unsigned int suwcnt = SVAL(inbuf, smb_suwcnt); - unsigned int tran_call = SVAL(inbuf, smb_setup0); - char *params = NULL, *data = NULL; - unsigned int num_params, num_params_sofar, num_data, num_data_sofar; - START_PROFILE(SMBtrans2); - - if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) { - /* Queue this open message as we are the process of an - * oplock break. */ - - DEBUG(2,("reply_trans2: queueing message trans2open due to being ")); - DEBUGADD(2,( "in oplock break state.\n")); - - push_oplock_pending_smb_message(inbuf, length); - END_PROFILE(SMBtrans2); - return -1; - } - - if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN) - && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) { - END_PROFILE(SMBtrans2); - return ERROR_DOS(ERRSRV,ERRaccess); - } - - outsize = set_message(outbuf,0,0,True); - - /* All trans2 messages we handle have smb_sucnt == 1 - ensure this - is so as a sanity check */ - if (suwcnt != 1) { - /* - * Need to have rc=0 for ioctl to get job id for OS/2. - * Network printing will fail if function is not successful. - * Similar function in reply.c will be used if protocol - * is LANMAN1.0 instead of LM1.2X002. - * Until DosPrintSetJobInfo with PRJINFO3 is supported, - * outbuf doesn't have to be set(only job id is used). - */ - if ( (suwcnt == 4) && (tran_call == TRANSACT2_IOCTL) && - (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && - (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { - DEBUG(2,("Got Trans2 DevIOctl jobid\n")); - } else { - DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt)); - DEBUG(2,("Transaction is %d\n",tran_call)); - END_PROFILE(SMBtrans2); - ERROR_DOS(ERRDOS,ERRinvalidparam); - } - } - - /* Allocate the space for the maximum needed parameters and data */ - if (total_params > 0) - params = (char *)malloc(total_params); - if (total_data > 0) - data = (char *)malloc(total_data); - - if ((total_params && !params) || (total_data && !data)) { - DEBUG(2,("Out of memory in reply_trans2\n")); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBtrans2); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - /* Copy the param and data bytes sent with this request into - the params buffer */ - num_params = num_params_sofar = SVAL(inbuf,smb_pscnt); - num_data = num_data_sofar = SVAL(inbuf, smb_dscnt); - - if (num_params > total_params || num_data > total_data) - exit_server("invalid params in reply_trans2"); - - if(params) { - unsigned int psoff = SVAL(inbuf, smb_psoff); - if ((psoff + num_params < psoff) || (psoff + num_params < num_params)) - goto bad_param; - if ((smb_base(inbuf) + psoff + num_params > inbuf + length) || - (smb_base(inbuf) + psoff + num_params < smb_base(inbuf))) - goto bad_param; - memcpy( params, smb_base(inbuf) + psoff, num_params); - } - if(data) { - unsigned int dsoff = SVAL(inbuf, smb_dsoff); - if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data)) - goto bad_param; - if ((smb_base(inbuf) + dsoff + num_data > inbuf + length) || - (smb_base(inbuf) + dsoff + num_data < smb_base(inbuf))) - goto bad_param; - memcpy( data, smb_base(inbuf) + dsoff, num_data); - } - - srv_signing_trans_start(SVAL(inbuf,smb_mid)); - - if(num_data_sofar < total_data || num_params_sofar < total_params) { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - srv_signing_trans_stop(); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_trans2: send_smb failed."); - - while (num_data_sofar < total_data || - num_params_sofar < total_params) { - BOOL ret; - unsigned int param_disp; - unsigned int param_off; - unsigned int data_disp; - unsigned int data_off; - - ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); - - /* - * The sequence number for the trans reply is always - * based on the last secondary received. - */ - - srv_signing_trans_start(SVAL(inbuf,smb_mid)); - - if ((ret && - (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret) { - outsize = set_message(outbuf,0,0,True); - if(ret) - DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n")); - else - DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n", - (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - goto bad_param; - } - - /* Revise total_params and total_data in case - they have changed downwards */ - if (SVAL(inbuf, smb_tpscnt) < total_params) - total_params = SVAL(inbuf, smb_tpscnt); - if (SVAL(inbuf, smb_tdscnt) < total_data) - total_data = SVAL(inbuf, smb_tdscnt); - - num_params = SVAL(inbuf,smb_spscnt); - param_off = SVAL(inbuf, smb_spsoff); - param_disp = SVAL(inbuf, smb_spsdisp); - num_params_sofar += num_params; - - num_data = SVAL(inbuf, smb_sdscnt); - data_off = SVAL(inbuf, smb_sdsoff); - data_disp = SVAL(inbuf, smb_sdsdisp); - num_data_sofar += num_data; - - if (num_params_sofar > total_params || num_data_sofar > total_data) - goto bad_param; - - if (num_params) { - if (param_disp + num_params >= total_params) - goto bad_param; - if ((param_disp + num_params < param_disp) || - (param_disp + num_params < num_params)) - goto bad_param; - if (param_disp > total_params) - goto bad_param; - if ((smb_base(inbuf) + param_off + num_params >= inbuf + bufsize) || - (smb_base(inbuf) + param_off + num_params < smb_base(inbuf))) - goto bad_param; - if (params + param_disp < params) - goto bad_param; - - memcpy( ¶ms[param_disp], smb_base(inbuf) + param_off, num_params); - } - if (num_data) { - if (data_disp + num_data >= total_data) - goto bad_param; - if ((data_disp + num_data < data_disp) || - (data_disp + num_data < num_data)) - goto bad_param; - if (data_disp > total_data) - goto bad_param; - if ((smb_base(inbuf) + data_off + num_data >= inbuf + bufsize) || - (smb_base(inbuf) + data_off + num_data < smb_base(inbuf))) - goto bad_param; - if (data + data_disp < data) - goto bad_param; - - memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data); - } - } - } - - if (Protocol >= PROTOCOL_NT1) { - 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, 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, 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, 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, total_params, &data, total_data); - END_PROFILE_NESTED(Trans2_qfsinfo); - break; - -#ifdef HAVE_SYS_QUOTAS - case TRANSACT2_SETFSINFO: - START_PROFILE_NESTED(Trans2_setfsinfo); - outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, - ¶ms, total_params, &data, total_data); - END_PROFILE_NESTED(Trans2_setfsinfo); - break; -#endif - case TRANSACT2_QPATHINFO: - case TRANSACT2_QFILEINFO: - START_PROFILE_NESTED(Trans2_qpathinfo); - 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, 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, 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, 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, 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, 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, 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)); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBtrans2); - srv_signing_trans_stop(); - return ERROR_DOS(ERRSRV,ERRerror); - } - - /* As we do not know how many data packets will need to be - returned here the various call_trans2xxxx calls - must send their own. Thus a call_trans2xxx routine only - returns a value other than -1 when it wants to send - an error packet. - */ - - srv_signing_trans_stop(); - - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBtrans2); - return outsize; /* If a correct response was needed the - call_trans2xxx calls have already sent - it. If outsize != -1 then it is returning */ - - bad_param: - - srv_signing_trans_stop(); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBtrans2); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); -} diff --git a/source/smbd/uid.c b/source/smbd/uid.c deleted file mode 100644 index ff3dd1a56ef..00000000000 --- a/source/smbd/uid.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - Unix SMB/CIFS implementation. - uid/user handling - Copyright (C) Andrew Tridgell 1992-1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* what user is current? */ -extern struct current_user current_user; - -/**************************************************************************** - Become the guest user without changing the security context stack. -****************************************************************************/ - -BOOL change_to_guest(void) -{ - static struct passwd *pass=NULL; - - if (!pass) { - /* Don't need to free() this as its stored in a static */ - pass = getpwnam_alloc(lp_guestaccount()); - if (!pass) - return(False); - } - -#ifdef AIX - /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before - setting IDs */ - initgroups(pass->pw_name, pass->pw_gid); -#endif - - set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL, NULL); - - current_user.conn = NULL; - current_user.vuid = UID_FIELD_INVALID; - - passwd_free(&pass); - - return True; -} - -/**************************************************************************** - Readonly share for this user ? -****************************************************************************/ - -static BOOL is_share_read_only_for_user(connection_struct *conn, user_struct *vuser) -{ - char **list; - const char *service = lp_servicename(conn->service); - BOOL read_only_ret = lp_readonly(conn->service); - - if (!service) - return read_only_ret; - - str_list_copy(&list, lp_readlist(conn->service)); - if (list) { - if (!str_list_sub_basic(list, vuser->user.smb_name) ) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: read list substitution failed\n")); - } - if (!str_list_substitute(list, "%S", service)) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: read list service substitution failed\n")); - } - if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) { - read_only_ret = True; - } - str_list_free(&list); - } - - str_list_copy(&list, lp_writelist(conn->service)); - if (list) { - if (!str_list_sub_basic(list, vuser->user.smb_name) ) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: write list substitution failed\n")); - } - if (!str_list_substitute(list, "%S", service)) { - DEBUG(0, ("is_share_read_only_for_user: ERROR: write list service substitution failed\n")); - } - if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) { - read_only_ret = False; - } - str_list_free(&list); - } - - DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user %s\n", - service, read_only_ret ? "read-only" : "read-write", vuser->user.unix_name )); - - return read_only_ret; -} - -/******************************************************************* - Check if a username is OK. -********************************************************************/ - -static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) -{ - unsigned int i; - struct vuid_cache_entry *ent = NULL; - BOOL readonly_share; - - for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) { - if (conn->vuid_cache.array[i].vuid == vuser->vuid) { - ent = &conn->vuid_cache.array[i]; - conn->read_only = ent->read_only; - conn->admin_user = ent->admin_user; - return(True); - } - } - - if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups)) - return(False); - - readonly_share = is_share_read_only_for_user(conn, vuser); - - if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) { - return False; - } - - i = conn->vuid_cache.entries % VUID_CACHE_SIZE; - if (conn->vuid_cache.entries < VUID_CACHE_SIZE) - conn->vuid_cache.entries++; - - ent = &conn->vuid_cache.array[i]; - ent->vuid = vuser->vuid; - ent->read_only = readonly_share; - - if (user_in_list(vuser->user.unix_name ,lp_admin_users(conn->service), vuser->groups, vuser->n_groups)) { - ent->admin_user = True; - } else { - ent->admin_user = False; - } - - conn->read_only = ent->read_only; - conn->admin_user = ent->admin_user; - - return(True); -} - -/**************************************************************************** - Become the user of a connection number without changing the security context - stack, but modify the currnet_user entries. -****************************************************************************/ - -BOOL change_to_user(connection_struct *conn, uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - int snum; - gid_t gid; - uid_t uid; - char group_c; - BOOL must_free_token_priv = False; - NT_USER_TOKEN *token = NULL; - PRIVILEGE_SET *privs = NULL; - - if (!conn) { - DEBUG(2,("change_to_user: Connection not open\n")); - return(False); - } - - /* - * We need a separate check in security=share mode due to vuid - * always being UID_FIELD_INVALID. If we don't do this then - * in share mode security we are *always* changing uid's between - * SMB's - this hurts performance - Badly. - */ - - if((lp_security() == SEC_SHARE) && (current_user.conn == conn) && - (current_user.uid == conn->uid)) { - 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,("change_to_user: Skipping user change - already user\n")); - return(True); - } - - snum = SNUM(conn); - - if (conn->force_user) /* security = share sets this too */ { - uid = conn->uid; - gid = conn->gid; - current_user.groups = conn->groups; - current_user.ngroups = conn->ngroups; - token = conn->nt_user_token; - privs = conn->privs; - } else if ((vuser) && check_user_ok(conn, vuser, snum)) { - uid = conn->admin_user ? 0 : vuser->uid; - gid = vuser->gid; - current_user.ngroups = vuser->n_groups; - current_user.groups = vuser->groups; - token = vuser->nt_user_token; - privs = vuser->privs; - } else { - DEBUG(2,("change_to_user: Invalid vuid used %d or vuid not permitted access to share.\n",vuid)); - return False; - } - - /* - * See if we should force group for this service. - * If so this overrides any group set in the force - * user code. - */ - - if((group_c = *lp_force_group(snum))) { - BOOL is_guest = False; - - if(group_c == '+') { - - /* - * Only force group if the user is a member of - * the service group. Check the group memberships for - * this user (we already have this) to - * see if we should force the group. - */ - - int i; - for (i = 0; i < current_user.ngroups; i++) { - if (current_user.groups[i] == conn->gid) { - gid = conn->gid; - break; - } - } - } else { - gid = conn->gid; - } - - /* - * We've changed the group list in the token - we must - * re-create it. - */ - - if (vuser && vuser->guest) - is_guest = True; - - token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest); - if (!token) { - DEBUG(1, ("change_to_user: create_nt_token failed!\n")); - return False; - } - pdb_get_privilege_set(token->user_sids, token->num_sids, privs); - must_free_token_priv = True; - } - - set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token, privs); - - /* - * Free the new token (as set_sec_ctx copies it). - */ - - if (must_free_token_priv) { - delete_nt_token(&token); - destroy_privilege(&privs); - } - - current_user.conn = conn; - current_user.vuid = vuid; - - DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n", - (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); - - return(True); -} - -/**************************************************************************** - Go back to being root without changing the security context stack, - but modify the current_user entries. -****************************************************************************/ - -BOOL change_to_root_user(void) -{ - set_root_sec_ctx(); - - 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; - current_user.vuid = UID_FIELD_INVALID; - - return(True); -} - -/**************************************************************************** - Become the user of an authenticated connected named pipe. - When this is called we are currently running as the connection - user. Doesn't modify current_user. -****************************************************************************/ - -BOOL become_authenticated_pipe_user(pipes_struct *p) -{ - 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, p->pipe_user.privs); - - return True; -} - -/**************************************************************************** - 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. Doesn't modify - current_user. -****************************************************************************/ - -BOOL unbecome_authenticated_pipe_user(void) -{ - return pop_sec_ctx(); -} - -/**************************************************************************** - 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; -} - -/**************************************************************************** - 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(); -} - -/* Unbecome the root user */ - -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; -} - diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c deleted file mode 100644 index a521d0113d4..00000000000 --- a/source/smbd/utmp.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - Unix SMB/CIFS implementation. - utmp routines - Copyright (C) T.D.Lee@durham.ac.uk 1999 - Heavily modified by Andrew Bartlett and Tridge, April 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/**************************************************************************** -Reflect connection status in utmp/wtmp files. - T.D.Lee@durham.ac.uk September 1999 - - With grateful thanks since then to many who have helped port it to - different operating systems. The variety of OS quirks thereby - uncovered is amazing... - -Hints for porting: - o Always attempt to use programmatic interface (pututline() etc.) - Indeed, at present only programmatic use is supported. - o The only currently supported programmatic interface to "wtmp{,x}" - is through "updwtmp*()" routines. - o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable. - o The HAVE_* items should identify supported features. - o If at all possible, avoid "if defined(MY-OS)" constructions. - -OS observations and status: - Almost every OS seems to have its own quirks. - - Solaris 2.x: - Tested on 2.6 and 2.7; should be OK on other flavours. - AIX: - Apparently has utmpx.h but doesn't implement. - OSF: - Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?) - Redhat 6: - utmpx.h seems not to set default filenames. non-x better. - IRIX 6.5: - Not tested. Appears to have "x". - HP-UX 9.x: - Not tested. Appears to lack "x". - HP-UX 10.x: - Not tested. - "updwtmp*()" routines seem absent, so no current wtmp* support. - Has "ut_addr": probably trivial to implement (although remember - that IPv6 is coming...). - - FreeBSD: - No "putut*()" type of interface. - No "ut_type" and associated defines. - Write files directly. Alternatively use its login(3)/logout(3). - SunOS 4: - Not tested. Resembles FreeBSD, but no login()/logout(). - -lastlog: - Should "lastlog" files, if any, be updated? - BSD systems (SunOS 4, FreeBSD): - o Prominent mention on man pages. - System-V (e.g. Solaris 2): - o No mention on man pages, even under "man -k". - o Has a "/var/adm/lastlog" file, but pututxline() etc. seem - not to touch it. - o Despite downplaying (above), nevertheless has <lastlog.h>. - So perhaps UN*X "lastlog" facility is intended for tty/terminal only? - -Notes: - Each connection requires a small number (starting at 0, working up) - to represent the line. This must be unique within and across all - smbd processes. It is the 'id_num' from Samba's session.c code. - - The 4 byte 'ut_id' component is vital to distinguish connections, - of which there could be several hundred or even thousand. - Entries seem to be printable characters, with optional NULL pads. - - We need to be distinct from other entries in utmp/wtmp. - - Observed things: therefore avoid them. Add to this list please. - From Solaris 2.x (because that's what I have): - 'sN' : run-levels; N: [0-9] - 'co' : console - 'CC' : arbitrary things; C: [a-z] - 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z] - 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z] - '/NNN' : Solaris CDE - 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff) - Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp", - but differences have been seen. - - Arbitrarily I have chosen to use a distinctive 'SM' for the - first two bytes. - - The remaining two bytes encode the session 'id_num' (see above). - Our caller (session.c) should note our 16-bit limitation. - -****************************************************************************/ - -#ifndef WITH_UTMP -/* - * Not WITH_UTMP? Simply supply dummy routines. - */ - -void sys_utmp_claim(const char *username, const char *hostname, - struct in_addr *ipaddr, - const char *id_str, int id_num) -{} - -void sys_utmp_yield(const char *username, const char *hostname, - struct in_addr *ipaddr, - const char *id_str, int id_num) -{} - -#else /* WITH_UTMP */ - -#include <utmp.h> - -#ifdef HAVE_UTMPX_H -#include <utmpx.h> -#endif - -/* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */ -/* Some System-V systems (e.g. Solaris 2) declare this too. */ -#ifdef HAVE_LASTLOG_H -#include <lastlog.h> -#endif - -/**************************************************************************** - Default paths to various {u,w}tmp{,x} files. -****************************************************************************/ - -#ifdef HAVE_UTMPX_H - -static const char *ux_pathname = -# if defined (UTMPX_FILE) - UTMPX_FILE ; -# elif defined (_UTMPX_FILE) - _UTMPX_FILE ; -# elif defined (_PATH_UTMPX) - _PATH_UTMPX ; -# else - "" ; -# endif - -static const char *wx_pathname = -# if defined (WTMPX_FILE) - WTMPX_FILE ; -# elif defined (_WTMPX_FILE) - _WTMPX_FILE ; -# elif defined (_PATH_WTMPX) - _PATH_WTMPX ; -# else - "" ; -# endif - -#endif /* HAVE_UTMPX_H */ - -static const char *ut_pathname = -# if defined (UTMP_FILE) - UTMP_FILE ; -# elif defined (_UTMP_FILE) - _UTMP_FILE ; -# elif defined (_PATH_UTMP) - _PATH_UTMP ; -# else - "" ; -# endif - -static const char *wt_pathname = -# if defined (WTMP_FILE) - WTMP_FILE ; -# elif defined (_WTMP_FILE) - _WTMP_FILE ; -# elif defined (_PATH_WTMP) - _PATH_WTMP ; -# else - "" ; -# endif - -/* BSD-like systems might want "lastlog" support. */ -/* *** Not yet implemented */ -#ifndef HAVE_PUTUTLINE /* see "pututline_my()" */ -static const char *ll_pathname = -# if defined (_PATH_LASTLOG) /* what other names (if any?) */ - _PATH_LASTLOG ; -# else - "" ; -# endif /* _PATH_LASTLOG */ -#endif /* HAVE_PUTUTLINE */ - -/* - * Get name of {u,w}tmp{,x} file. - * return: fname contains filename - * Possibly empty if this code not yet ported to this system. - * - * utmp{,x}: try "utmp dir", then default (a define) - * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define) - */ -static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default) -{ - pstring dirname; - - pstrcpy(dirname, ""); - - /* For w-files, first look for explicit "wtmp dir" */ - if (uw_name[0] == 'w') { - pstrcpy(dirname,lp_wtmpdir()); - trim_char(dirname,'\0','/'); - } - - /* For u-files and non-explicit w-dir, look for "utmp dir" */ - if (dirname == 0 || strlen(dirname) == 0) { - pstrcpy(dirname,lp_utmpdir()); - trim_char(dirname,'\0','/'); - } - - /* If explicit directory above, use it */ - if (dirname != 0 && strlen(dirname) != 0) { - pstrcpy(fname, dirname); - pstrcat(fname, "/"); - pstrcat(fname, uw_name); - return; - } - - /* No explicit directory: attempt to use default paths */ - if (strlen(uw_default) == 0) { - /* No explicit setting, no known default. - * Has it yet been ported to this OS? - */ - DEBUG(2,("uw_pathname: unable to determine pathname\n")); - } - pstrcpy(fname, uw_default); -} - -#ifndef HAVE_PUTUTLINE - -/**************************************************************************** - 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")); - /* BSD implementor: may want to consider (or not) adjusting "lastlog" */ -} -#endif /* HAVE_PUTUTLINE */ - -#ifndef HAVE_UPDWTMP - -/**************************************************************************** - 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; - struct stat buf; - - if (! claim) { - /* - * BSD-like systems: - * may use empty ut_name to distinguish a logout record. - * - * May need "if defined(SUNOS4)" etc. around some of these, - * but try to avoid if possible. - * - * SunOS 4: - * man page indicates ut_name and ut_host both NULL - * FreeBSD 4.0: - * man page appears not to specify (hints non-NULL) - * A correspondent suggest at least ut_name should be NULL - */ -#if defined(HAVE_UT_UT_NAME) - memset((char *)&u->ut_name, '\0', sizeof(u->ut_name)); -#endif -#if defined(HAVE_UT_UT_HOST) - memset((char *)&u->ut_host, '\0', sizeof(u->ut_host)); -#endif - } - /* Stolen from logwtmp function in libutil. - * May be more locking/blocking is needed? - */ - if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0) - return; - if (fstat(fd, &buf) == 0) { - if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp)) - (void) ftruncate(fd, buf.st_size); - } - (void) close(fd); -} -#endif /* HAVE_UPDWTMP */ - -/**************************************************************************** - Update via utmp/wtmp (not utmpx/wtmpx). -****************************************************************************/ - -static void utmp_nox_update(struct utmp *u, BOOL claim) -{ - pstring uname, wname; -#if defined(PUTUTLINE_RETURNS_UTMP) - struct utmp *urc; -#endif /* PUTUTLINE_RETURNS_UTMP */ - - uw_pathname(uname, "utmp", ut_pathname); - DEBUG(2,("utmp_nox_update: uname:%s\n", uname)); - -#ifdef HAVE_PUTUTLINE - if (strlen(uname) != 0) { - utmpname(uname); - } - -# if defined(PUTUTLINE_RETURNS_UTMP) - setutent(); - urc = pututline(u); - endutent(); - if (urc == NULL) { - DEBUG(2,("utmp_nox_update: pututline() failed\n")); - return; - } -# else /* PUTUTLINE_RETURNS_UTMP */ - setutent(); - pututline(u); - endutent(); -# endif /* PUTUTLINE_RETURNS_UTMP */ - -#else /* HAVE_PUTUTLINE */ - if (strlen(uname) != 0) { - pututline_my(uname, u, claim); - } -#endif /* HAVE_PUTUTLINE */ - - uw_pathname(wname, "wtmp", wt_pathname); - DEBUG(2,("utmp_nox_update: wname:%s\n", wname)); - if (strlen(wname) != 0) { -#ifdef HAVE_UPDWTMP - updwtmp(wname, u); - /* - * updwtmp() and the newer updwtmpx() may be unsymmetrical. - * At least one OS, Solaris 2.x declares the former in the - * "utmpx" (latter) file and context. - * In the Solaris case this is irrelevant: it has both and - * we always prefer the "x" case, so doesn't come here. - * But are there other systems, with no "x", which lack - * updwtmp() perhaps? - */ -#else - updwtmp_my(wname, u, claim); -#endif /* HAVE_UPDWTMP */ - } -} - -/**************************************************************************** - 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, 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, 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, claim); -#else - pstring uname, wname; - struct utmpx ux, *uxrc; - - 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; -#endif -#if defined(HAVE_UT_UT_HOST) - utmp_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host)); -#endif - - uw_pathname(uname, "utmpx", ux_pathname); - uw_pathname(wname, "wtmpx", wx_pathname); - DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname)); - /* - * Check for either uname or wname being empty. - * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't - * define default filenames. - * Also, our local installation has not provided an override. - * 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, claim); - } else { - utmpxname(uname); - setutxent(); - uxrc = pututxline(&ux); - endutxent(); - if (uxrc == NULL) { - DEBUG(2,("utmp_update: pututxline() failed\n")); - return; - } - updwtmpx(wname, &ux); - } -#endif /* HAVE_UTMPX_H */ -} - -#if defined(HAVE_UT_UT_ID) -/**************************************************************************** - Encode the unique connection number into "ut_id". -****************************************************************************/ - -static int ut_id_encode(int i, char *fourbyte) -{ - int nbase; - const char *ut_id_encstr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - fourbyte[0] = 'S'; - fourbyte[1] = 'M'; - -/* - * Encode remaining 2 bytes from 'i'. - * 'ut_id_encstr' is the character set on which modulo arithmetic is done. - * Example: digits would produce the base-10 numbers from '001'. - */ - nbase = strlen(ut_id_encstr); - - fourbyte[3] = ut_id_encstr[i % nbase]; - i /= nbase; - fourbyte[2] = ut_id_encstr[i % nbase]; - i /= nbase; - - return(i); /* 0: good; else overflow */ -} -#endif /* defined(HAVE_UT_UT_ID) */ - - -/* - fill a system utmp structure given all the info we can gather -*/ -static BOOL sys_utmp_fill(struct utmp *u, - const char *username, const char *hostname, - struct in_addr *ipaddr, - const char *id_str, int id_num) -{ - struct timeval timeval; - - /* - * ut_name, ut_user: - * Several (all?) systems seems to define one as the other. - * It is easier and clearer simply to let the following take its course, - * rather than to try to detect and optimise. - */ -#if defined(HAVE_UT_UT_USER) - utmp_strcpy(u->ut_user, username, sizeof(u->ut_user)); -#elif defined(HAVE_UT_UT_NAME) - utmp_strcpy(u->ut_name, username, sizeof(u->ut_name)); -#endif - - /* - * ut_line: - * If size limit proves troublesome, then perhaps use "ut_id_encode()". - */ - if (strlen(id_str) > sizeof(u->ut_line)) { - DEBUG(1,("id_str [%s] is too long for %lu char utmp field\n", - id_str, (unsigned long)sizeof(u->ut_line))); - return False; - } - utmp_strcpy(u->ut_line, id_str, sizeof(u->ut_line)); - -#if defined(HAVE_UT_UT_PID) - u->ut_pid = sys_getpid(); -#endif - -/* - * ut_time, ut_tv: - * Some have one, some the other. Many have both, but defined (aliased). - * It is easier and clearer simply to let the following take its course. - * But note that we do the more precise ut_tv as the final assignment. - */ -#if defined(HAVE_UT_UT_TIME) - gettimeofday(&timeval, NULL); - u->ut_time = timeval.tv_sec; -#elif defined(HAVE_UT_UT_TV) - gettimeofday(&timeval, NULL); - u->ut_tv = timeval; -#else -#error "with-utmp must have UT_TIME or UT_TV" -#endif - -#if defined(HAVE_UT_UT_HOST) - utmp_strcpy(u->ut_host, hostname, sizeof(u->ut_host)); -#endif -#if defined(HAVE_UT_UT_ADDR) - if (ipaddr) - u->ut_addr = ipaddr->s_addr; - /* - * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20. - * Volunteer to implement, please ... - */ -#endif - -#if defined(HAVE_UT_UT_ID) - if (ut_id_encode(id_num, u->ut_id) != 0) { - DEBUG(1,("utmp_fill: cannot encode id %d\n", id_num)); - return False; - } -#endif - - return True; -} - -/**************************************************************************** - Close a connection. -****************************************************************************/ - -void sys_utmp_yield(const char *username, const char *hostname, - struct in_addr *ipaddr, - const char *id_str, int id_num) -{ - struct utmp u; - - ZERO_STRUCT(u); - -#if defined(HAVE_UT_UT_EXIT) - u.ut_exit.e_termination = 0; - u.ut_exit.e_exit = 0; -#endif - -#if defined(HAVE_UT_UT_TYPE) - u.ut_type = DEAD_PROCESS; -#endif - - if (!sys_utmp_fill(&u, username, hostname, ipaddr, id_str, id_num)) return; - - sys_utmp_update(&u, NULL, False); -} - -/**************************************************************************** - Claim a entry in whatever utmp system the OS uses. -****************************************************************************/ - -void sys_utmp_claim(const char *username, const char *hostname, - struct in_addr *ipaddr, - const char *id_str, int id_num) -{ - struct utmp u; - - ZERO_STRUCT(u); - -#if defined(HAVE_UT_UT_TYPE) - u.ut_type = USER_PROCESS; -#endif - - if (!sys_utmp_fill(&u, username, hostname, ipaddr, id_str, id_num)) return; - - sys_utmp_update(&u, hostname, True); -} - -#endif /* WITH_UTMP */ diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c deleted file mode 100644 index 5393dfc7556..00000000000 --- a/source/smbd/vfs-wrap.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Wrap disk only vfs functions to sidestep dodgy compilers. - Copyright (C) Tim Potter 1998 - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_VFS - - -/* Check for NULL pointer parameters in vfswrap_* functions */ - -/* We don't want to have NULL function pointers lying around. Someone - is sure to try and execute them. These stubs are used to prevent - this possibility. */ - -int vfswrap_dummy_connect(vfs_handle_struct *handle, connection_struct *conn, const char *service, const char *user) -{ - return 0; /* Return >= 0 for success */ -} - -void vfswrap_dummy_disconnect(vfs_handle_struct *handle, connection_struct *conn) -{ -} - -/* Disk operations */ - -SMB_BIG_UINT vfswrap_disk_free(vfs_handle_struct *handle, connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize, - SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) -{ - SMB_BIG_UINT result; - - result = sys_disk_free(path, small_query, bsize, dfree, dsize); - return result; -} - -int vfswrap_get_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) -{ -#ifdef HAVE_SYS_QUOTAS - int result; - - START_PROFILE(syscall_get_quota); - result = sys_get_quota(conn->connectpath, qtype, id, qt); - END_PROFILE(syscall_get_quota); - return result; -#else - errno = ENOSYS; - return -1; -#endif -} - -int vfswrap_set_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) -{ -#ifdef HAVE_SYS_QUOTAS - int result; - - START_PROFILE(syscall_set_quota); - result = sys_set_quota(conn->connectpath, qtype, id, qt); - END_PROFILE(syscall_set_quota); - return result; -#else - errno = ENOSYS; - return -1; -#endif -} - -int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels) -{ - errno = ENOSYS; - return -1; /* Not implemented. */ -} - -/* Directory operations */ - -DIR *vfswrap_opendir(vfs_handle_struct *handle, connection_struct *conn, const char *fname) -{ - DIR *result; - - START_PROFILE(syscall_opendir); - result = opendir(fname); - END_PROFILE(syscall_opendir); - return result; -} - -struct dirent *vfswrap_readdir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp) -{ - struct dirent *result; - - START_PROFILE(syscall_readdir); - result = readdir(dirp); - END_PROFILE(syscall_readdir); - return result; -} - -int vfswrap_mkdir(vfs_handle_struct *handle, connection_struct *conn, const char *path, mode_t mode) -{ - int result; - BOOL has_dacl = False; - - START_PROFILE(syscall_mkdir); - - if (lp_inherit_acls(SNUM(conn)) && (has_dacl = directory_has_default_acl(conn, parent_dirname(path)))) - mode = 0777; - - result = mkdir(path, mode); - - if (result == 0 && !has_dacl) { - /* - * We need to do this as the default behavior of POSIX ACLs - * is to set the mask to be the requested group permission - * bits, not the group permission bits to be the requested - * group permission bits. This is not what we want, as it will - * mess up any inherited ACL bits that were set. JRA. - */ - int saved_errno = errno; /* We may get ENOSYS */ - if ((SMB_VFS_CHMOD_ACL(conn, path, mode) == -1) && (errno == ENOSYS)) - errno = saved_errno; - } - - END_PROFILE(syscall_mkdir); - return result; -} - -int vfswrap_rmdir(vfs_handle_struct *handle, connection_struct *conn, const char *path) -{ - int result; - - START_PROFILE(syscall_rmdir); - result = rmdir(path); - END_PROFILE(syscall_rmdir); - return result; -} - -int vfswrap_closedir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp) -{ - int result; - - START_PROFILE(syscall_closedir); - result = closedir(dirp); - END_PROFILE(syscall_closedir); - return result; -} - -/* File operations */ - -int vfswrap_open(vfs_handle_struct *handle, connection_struct *conn, const char *fname, int flags, mode_t mode) -{ - int result; - - START_PROFILE(syscall_open); - result = sys_open(fname, flags, mode); - END_PROFILE(syscall_open); - return result; -} - -int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp, int fd) -{ - int result; - - START_PROFILE(syscall_close); - - result = close(fd); - END_PROFILE(syscall_close); - return result; -} - -ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, size_t n) -{ - ssize_t result; - - START_PROFILE_BYTES(syscall_read, n); - result = sys_read(fd, data, n); - END_PROFILE(syscall_read); - return result; -} - -ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, - size_t n, SMB_OFF_T offset) -{ - ssize_t result; - -#if defined(HAVE_PREAD) || defined(HAVE_PREAD64) - START_PROFILE_BYTES(syscall_pread, n); - result = sys_pread(fd, data, n, offset); - END_PROFILE(syscall_pread); - - if (result == -1 && errno == ESPIPE) { - /* Maintain the fiction that pipes can be seeked (sought?) on. */ - result = SMB_VFS_READ(fsp, fd, data, n); - fsp->pos = 0; - } - -#else /* HAVE_PREAD */ - SMB_OFF_T curr; - int lerrno; - - curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); - if (curr == -1 && errno == ESPIPE) { - /* Maintain the fiction that pipes can be seeked (sought?) on. */ - result = SMB_VFS_READ(fsp, fd, data, n); - fsp->pos = 0; - return result; - } - - if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) { - return -1; - } - - errno = 0; - result = SMB_VFS_READ(fsp, fd, data, n); - lerrno = errno; - - SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET); - errno = lerrno; - -#endif /* HAVE_PREAD */ - - return result; -} - -ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, size_t n) -{ - ssize_t result; - - START_PROFILE_BYTES(syscall_write, n); - result = sys_write(fd, data, n); - END_PROFILE(syscall_write); - return result; -} - -ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, - size_t n, SMB_OFF_T offset) -{ - ssize_t result; - -#if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64) - START_PROFILE_BYTES(syscall_pwrite, n); - result = sys_pwrite(fd, data, n, offset); - END_PROFILE(syscall_pwrite); - - if (result == -1 && errno == ESPIPE) { - /* Maintain the fiction that pipes can be sought on. */ - result = SMB_VFS_WRITE(fsp, fd, data, n); - } - -#else /* HAVE_PWRITE */ - SMB_OFF_T curr; - int lerrno; - - curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); - if (curr == -1) { - return -1; - } - - if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) { - return -1; - } - - result = SMB_VFS_WRITE(fsp, fd, data, n); - lerrno = errno; - - SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET); - errno = lerrno; - -#endif /* HAVE_PWRITE */ - - return result; -} - -SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, int filedes, SMB_OFF_T offset, int whence) -{ - SMB_OFF_T result = 0; - - START_PROFILE(syscall_lseek); - - /* Cope with 'stat' file opens. */ - if (filedes != -1) - result = sys_lseek(filedes, offset, whence); - - /* - * We want to maintain the fiction that we can seek - * on a fifo for file system purposes. This allows - * people to set up UNIX fifo's that feed data to Windows - * applications. JRA. - */ - - if((result == -1) && (errno == ESPIPE)) { - result = 0; - errno = 0; - } - - END_PROFILE(syscall_lseek); - return result; -} - -ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, int fromfd, const DATA_BLOB *hdr, - SMB_OFF_T offset, size_t n) -{ - ssize_t result; - - START_PROFILE_BYTES(syscall_sendfile, n); - result = sys_sendfile(tofd, fromfd, hdr, offset, n); - END_PROFILE(syscall_sendfile); - return result; -} - -/********************************************************* - For rename across filesystems Patch from Warren Birnbaum - <warrenb@hpcvscdp.cv.hp.com> -**********************************************************/ - -static int copy_reg(const char *source, const char *dest) -{ - SMB_STRUCT_STAT source_stats; - int saved_errno; - int ifd = -1; - int ofd = -1; - - if (sys_lstat (source, &source_stats) == -1) - return -1; - - if (!S_ISREG (source_stats.st_mode)) - return -1; - - if((ifd = sys_open (source, O_RDONLY, 0)) < 0) - return -1; - - if (unlink (dest) && errno != ENOENT) - return -1; - -#ifdef O_NOFOLLOW - if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 ) -#else - if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 ) -#endif - goto err; - - if (transfer_file(ifd, ofd, (size_t)-1) == -1) - goto err; - - /* - * Try to preserve ownership. For non-root it might fail, but that's ok. - * But root probably wants to know, e.g. if NFS disallows it. - */ - -#ifdef HAVE_FCHOWN - if ((fchown(ofd, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) -#else - if ((chown(dest, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) -#endif - goto err; - - /* - * fchown turns off set[ug]id bits for non-root, - * so do the chmod last. - */ - -#if defined(HAVE_FCHMOD) - if (fchmod (ofd, source_stats.st_mode & 07777)) -#else - if (chmod (dest, source_stats.st_mode & 07777)) -#endif - goto err; - - if (close (ifd) == -1) - goto err; - - if (close (ofd) == -1) - return -1; - - /* Try to copy the old file's modtime and access time. */ - { - struct utimbuf tv; - - tv.actime = source_stats.st_atime; - tv.modtime = source_stats.st_mtime; - utime(dest, &tv); - } - - if (unlink (source) == -1) - return -1; - - return 0; - - err: - - saved_errno = errno; - if (ifd != -1) - close(ifd); - if (ofd != -1) - close(ofd); - errno = saved_errno; - return -1; -} - -int vfswrap_rename(vfs_handle_struct *handle, connection_struct *conn, const char *old, const char *new) -{ - int result; - - START_PROFILE(syscall_rename); - result = rename(old, new); - if (errno == EXDEV) { - /* Rename across filesystems needed. */ - result = copy_reg(old, new); - } - - END_PROFILE(syscall_rename); - return result; -} - -int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd) -{ -#ifdef HAVE_FSYNC - int result; - - START_PROFILE(syscall_fsync); - result = fsync(fd); - END_PROFILE(syscall_fsync); - return result; -#else - return 0; -#endif -} - -int vfswrap_stat(vfs_handle_struct *handle, connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf) -{ - int result; - - START_PROFILE(syscall_stat); - result = sys_stat(fname, sbuf); - END_PROFILE(syscall_stat); - return result; -} - -int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf) -{ - int result; - - START_PROFILE(syscall_fstat); - result = sys_fstat(fd, sbuf); - END_PROFILE(syscall_fstat); - return result; -} - -int vfswrap_lstat(vfs_handle_struct *handle, connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf) -{ - int result; - - START_PROFILE(syscall_lstat); - result = sys_lstat(path, sbuf); - END_PROFILE(syscall_lstat); - return result; -} - -int vfswrap_unlink(vfs_handle_struct *handle, connection_struct *conn, const char *path) -{ - int result; - - START_PROFILE(syscall_unlink); - result = unlink(path); - END_PROFILE(syscall_unlink); - return result; -} - -int vfswrap_chmod(vfs_handle_struct *handle, connection_struct *conn, const char *path, mode_t mode) -{ - int result; - - START_PROFILE(syscall_chmod); - - /* - * We need to do this due to the fact that the default POSIX ACL - * chmod modifies the ACL *mask* for the group owner, not the - * group owner bits directly. JRA. - */ - - - { - int saved_errno = errno; /* We might get ENOSYS */ - if ((result = SMB_VFS_CHMOD_ACL(conn, path, mode)) == 0) { - END_PROFILE(syscall_chmod); - return result; - } - /* Error - return the old errno. */ - errno = saved_errno; - } - - result = chmod(path, mode); - END_PROFILE(syscall_chmod); - return result; -} - -int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) -{ - int result; - - START_PROFILE(syscall_fchmod); - - /* - * We need to do this due to the fact that the default POSIX ACL - * chmod modifies the ACL *mask* for the group owner, not the - * group owner bits directly. JRA. - */ - - { - int saved_errno = errno; /* We might get ENOSYS */ - if ((result = SMB_VFS_FCHMOD_ACL(fsp, fd, mode)) == 0) { - END_PROFILE(syscall_chmod); - return result; - } - /* Error - return the old errno. */ - errno = saved_errno; - } - -#if defined(HAVE_FCHMOD) - result = fchmod(fd, mode); -#else - result = -1; - errno = ENOSYS; -#endif - - END_PROFILE(syscall_fchmod); - return result; -} - -int vfswrap_chown(vfs_handle_struct *handle, connection_struct *conn, const char *path, uid_t uid, gid_t gid) -{ - int result; - - START_PROFILE(syscall_chown); - result = sys_chown(path, uid, gid); - END_PROFILE(syscall_chown); - return result; -} - -int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd, uid_t uid, gid_t gid) -{ -#ifdef HAVE_FCHOWN - int result; - - START_PROFILE(syscall_fchown); - result = fchown(fd, uid, gid); - END_PROFILE(syscall_fchown); - return result; -#else - errno = ENOSYS; - return -1; -#endif -} - -int vfswrap_chdir(vfs_handle_struct *handle, connection_struct *conn, const char *path) -{ - int result; - - START_PROFILE(syscall_chdir); - result = chdir(path); - END_PROFILE(syscall_chdir); - return result; -} - -char *vfswrap_getwd(vfs_handle_struct *handle, connection_struct *conn, char *path) -{ - char *result; - - START_PROFILE(syscall_getwd); - result = sys_getwd(path); - END_PROFILE(syscall_getwd); - return result; -} - -int vfswrap_utime(vfs_handle_struct *handle, connection_struct *conn, const char *path, struct utimbuf *times) -{ - int result; - - START_PROFILE(syscall_utime); - result = utime(path, times); - END_PROFILE(syscall_utime); - return result; -} - -/********************************************************************* - A version of ftruncate that will write the space on disk if strict - allocate is set. -**********************************************************************/ - -static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) -{ - SMB_STRUCT_STAT st; - SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); - unsigned char zero_space[4096]; - SMB_OFF_T space_to_write; - - if (currpos == -1) - return -1; - - if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) - return -1; - - space_to_write = len - st.st_size; - -#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 (SMB_VFS_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 = SMB_VFS_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 (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) - return -1; - - return 0; -} - -int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) -{ - int result = -1; - SMB_STRUCT_STAT st; - char c = 0; - SMB_OFF_T currpos; - - START_PROFILE(syscall_ftruncate); - - if (lp_strict_allocate(SNUM(fsp->conn))) { - result = strict_allocate_ftruncate(handle, 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; - - /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot - extend a file with ftruncate. Provide alternate implementation - for this */ - currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); - if (currpos == -1) { - goto done; - } - - /* Do an fstat to see if the file is longer than the requested - 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 (SMB_VFS_FSTAT(fsp, fd, &st) == -1) { - goto done; - } - -#ifdef S_ISFIFO - if (S_ISFIFO(st.st_mode)) { - result = 0; - goto done; - } -#endif - - if (st.st_size == len) { - result = 0; - goto done; - } - - if (st.st_size > len) { - /* the sys_ftruncate should have worked */ - goto done; - } - - if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1) - goto done; - - if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1) - goto done; - - /* Seek to where we were */ - if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) - goto done; - result = 0; - - done: - - END_PROFILE(syscall_ftruncate); - return result; -} - -BOOL vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) -{ - BOOL result; - - START_PROFILE(syscall_fcntl_lock); - result = fcntl_lock(fd, op, offset, count,type); - END_PROFILE(syscall_fcntl_lock); - return result; -} - -int vfswrap_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath) -{ - int result; - - START_PROFILE(syscall_symlink); - result = sys_symlink(oldpath, newpath); - END_PROFILE(syscall_symlink); - return result; -} - -int vfswrap_readlink(vfs_handle_struct *handle, connection_struct *conn, const char *path, char *buf, size_t bufsiz) -{ - int result; - - START_PROFILE(syscall_readlink); - result = sys_readlink(path, buf, bufsiz); - END_PROFILE(syscall_readlink); - return result; -} - -int vfswrap_link(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath) -{ - int result; - - START_PROFILE(syscall_link); - result = sys_link(oldpath, newpath); - END_PROFILE(syscall_link); - return result; -} - -int vfswrap_mknod(vfs_handle_struct *handle, connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev) -{ - int result; - - START_PROFILE(syscall_mknod); - result = sys_mknod(pathname, mode, dev); - END_PROFILE(syscall_mknod); - return result; -} - -char *vfswrap_realpath(vfs_handle_struct *handle, connection_struct *conn, const char *path, char *resolved_path) -{ - char *result; - - START_PROFILE(syscall_realpath); - result = sys_realpath(path, resolved_path); - END_PROFILE(syscall_realpath); - return result; -} - -size_t vfswrap_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info, SEC_DESC **ppdesc) -{ - size_t result; - - START_PROFILE(fget_nt_acl); - result = get_nt_acl(fsp, security_info, ppdesc); - END_PROFILE(fget_nt_acl); - return result; -} - -size_t vfswrap_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info, SEC_DESC **ppdesc) -{ - size_t result; - - START_PROFILE(get_nt_acl); - result = get_nt_acl(fsp, security_info, ppdesc); - END_PROFILE(get_nt_acl); - return result; -} - -BOOL vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd) -{ - BOOL result; - - START_PROFILE(fset_nt_acl); - result = set_nt_acl(fsp, security_info_sent, psd); - END_PROFILE(fset_nt_acl); - return result; -} - -BOOL vfswrap_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd) -{ - BOOL result; - - START_PROFILE(set_nt_acl); - result = set_nt_acl(fsp, security_info_sent, psd); - END_PROFILE(set_nt_acl); - return result; -} - -int vfswrap_chmod_acl(vfs_handle_struct *handle, connection_struct *conn, const char *name, mode_t mode) -{ -#ifdef HAVE_NO_ACL - errno = ENOSYS; - return -1; -#else - int result; - - START_PROFILE(chmod_acl); - result = chmod_acl(conn, name, mode); - END_PROFILE(chmod_acl); - return result; -#endif -} - -int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) -{ -#ifdef HAVE_NO_ACL - errno = ENOSYS; - return -1; -#else - int result; - - START_PROFILE(fchmod_acl); - result = fchmod_acl(fsp, fd, mode); - END_PROFILE(fchmod_acl); - return result; -#endif -} - -int vfswrap_sys_acl_get_entry(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) -{ - return sys_acl_get_entry(theacl, entry_id, entry_p); -} - -int vfswrap_sys_acl_get_tag_type(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) -{ - return sys_acl_get_tag_type(entry_d, tag_type_p); -} - -int vfswrap_sys_acl_get_permset(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) -{ - return sys_acl_get_permset(entry_d, permset_p); -} - -void * vfswrap_sys_acl_get_qualifier(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry_d) -{ - return sys_acl_get_qualifier(entry_d); -} - -SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, connection_struct *conn, const char *path_p, SMB_ACL_TYPE_T type) -{ - return sys_acl_get_file(path_p, type); -} - -SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd) -{ - return sys_acl_get_fd(fd); -} - -int vfswrap_sys_acl_clear_perms(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_PERMSET_T permset) -{ - return sys_acl_clear_perms(permset); -} - -int vfswrap_sys_acl_add_perm(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) -{ - return sys_acl_add_perm(permset, perm); -} - -char * vfswrap_sys_acl_to_text(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T theacl, ssize_t *plen) -{ - return sys_acl_to_text(theacl, plen); -} - -SMB_ACL_T vfswrap_sys_acl_init(vfs_handle_struct *handle, connection_struct *conn, int count) -{ - return sys_acl_init(count); -} - -int vfswrap_sys_acl_create_entry(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) -{ - return sys_acl_create_entry(pacl, pentry); -} - -int vfswrap_sys_acl_set_tag_type(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) -{ - return sys_acl_set_tag_type(entry, tagtype); -} - -int vfswrap_sys_acl_set_qualifier(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry, void *qual) -{ - return sys_acl_set_qualifier(entry, qual); -} - -int vfswrap_sys_acl_set_permset(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) -{ - return sys_acl_set_permset(entry, permset); -} - -int vfswrap_sys_acl_valid(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T theacl ) -{ - return sys_acl_valid(theacl ); -} - -int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, connection_struct *conn, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) -{ - return sys_acl_set_file(name, acltype, theacl); -} - -int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_ACL_T theacl) -{ - return sys_acl_set_fd(fd, theacl); -} - -int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, connection_struct *conn, const char *path) -{ - return sys_acl_delete_def_file(path); -} - -int vfswrap_sys_acl_get_perm(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) -{ - return sys_acl_get_perm(permset, perm); -} - -int vfswrap_sys_acl_free_text(vfs_handle_struct *handle, connection_struct *conn, char *text) -{ - return sys_acl_free_text(text); -} - -int vfswrap_sys_acl_free_acl(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T posix_acl) -{ - return sys_acl_free_acl(posix_acl); -} - -int vfswrap_sys_acl_free_qualifier(vfs_handle_struct *handle, connection_struct *conn, void *qualifier, SMB_ACL_TAG_T tagtype) -{ - return sys_acl_free_qualifier(qualifier, tagtype); -} - -/**************************************************************** - Extended attribute operations. -*****************************************************************/ - -ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,struct connection_struct *conn,const char *path, const char *name, void *value, size_t size) -{ - return sys_getxattr(path, name, value, size); -} - -ssize_t vfswrap_lgetxattr(struct vfs_handle_struct *handle,struct connection_struct *conn,const char *path, const char *name, void *value, size_t size) -{ - return sys_lgetxattr(path, name, value, size); -} - -ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size) -{ - return sys_fgetxattr(fd, name, value, size); -} - -ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size) -{ - return sys_listxattr(path, list, size); -} - -ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size) -{ - return sys_llistxattr(path, list, size); -} - -ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, char *list, size_t size) -{ - return sys_flistxattr(fd, list, size); -} - -int vfswrap_removexattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name) -{ - return sys_removexattr(path, name); -} - -int vfswrap_lremovexattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name) -{ - return sys_lremovexattr(path, name); -} - -int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name) -{ - return sys_fremovexattr(fd, name); -} - -int vfswrap_setxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags) -{ - return sys_setxattr(path, name, value, size, flags); -} - -int vfswrap_lsetxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags) -{ - return sys_lsetxattr(path, name, value, size, flags); -} - -int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags) -{ - return sys_fsetxattr(fd, name, value, size, flags); -} diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c deleted file mode 100644 index 4f3234775a2..00000000000 --- a/source/smbd/vfs.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - VFS initialisation and support functions - Copyright (C) Tim Potter 1999 - Copyright (C) Alexander Bokovoy 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - This work was sponsored by Optifacio Software Services, Inc. -*/ - -#include "includes.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_VFS - -struct vfs_init_function_entry { - char *name; - vfs_op_tuple *vfs_op_tuples; - struct vfs_init_function_entry *prev, *next; -}; - -static struct vfs_init_function_entry *backends = NULL; - -/* Some structures to help us initialise the vfs operations table */ - -struct vfs_syminfo { - char *name; - void *fptr; -}; - -/* Default vfs hooks. WARNING: The order of these initialisers is - very important. They must be in the same order as defined in - vfs.h. Change at your own peril. */ - -static struct vfs_ops default_vfs = { - - { - /* Disk operations */ - - vfswrap_dummy_connect, - vfswrap_dummy_disconnect, - vfswrap_disk_free, - vfswrap_get_quota, - vfswrap_set_quota, - vfswrap_get_shadow_copy_data, - - /* Directory operations */ - - vfswrap_opendir, - vfswrap_readdir, - vfswrap_mkdir, - vfswrap_rmdir, - vfswrap_closedir, - - /* File operations */ - - vfswrap_open, - vfswrap_close, - vfswrap_read, - vfswrap_pread, - vfswrap_write, - vfswrap_pwrite, - vfswrap_lseek, - vfswrap_sendfile, - vfswrap_rename, - vfswrap_fsync, - vfswrap_stat, - vfswrap_fstat, - vfswrap_lstat, - vfswrap_unlink, - vfswrap_chmod, - vfswrap_fchmod, - vfswrap_chown, - vfswrap_fchown, - vfswrap_chdir, - vfswrap_getwd, - vfswrap_utime, - vfswrap_ftruncate, - vfswrap_lock, - vfswrap_symlink, - vfswrap_readlink, - vfswrap_link, - vfswrap_mknod, - vfswrap_realpath, - - /* Windows ACL operations. */ - vfswrap_fget_nt_acl, - vfswrap_get_nt_acl, - vfswrap_fset_nt_acl, - vfswrap_set_nt_acl, - - /* POSIX ACL operations. */ - vfswrap_chmod_acl, - vfswrap_fchmod_acl, - - vfswrap_sys_acl_get_entry, - vfswrap_sys_acl_get_tag_type, - vfswrap_sys_acl_get_permset, - vfswrap_sys_acl_get_qualifier, - vfswrap_sys_acl_get_file, - vfswrap_sys_acl_get_fd, - vfswrap_sys_acl_clear_perms, - vfswrap_sys_acl_add_perm, - vfswrap_sys_acl_to_text, - vfswrap_sys_acl_init, - vfswrap_sys_acl_create_entry, - vfswrap_sys_acl_set_tag_type, - vfswrap_sys_acl_set_qualifier, - vfswrap_sys_acl_set_permset, - vfswrap_sys_acl_valid, - vfswrap_sys_acl_set_file, - vfswrap_sys_acl_set_fd, - vfswrap_sys_acl_delete_def_file, - vfswrap_sys_acl_get_perm, - vfswrap_sys_acl_free_text, - vfswrap_sys_acl_free_acl, - vfswrap_sys_acl_free_qualifier, - - /* EA operations. */ - vfswrap_getxattr, - vfswrap_lgetxattr, - vfswrap_fgetxattr, - vfswrap_listxattr, - vfswrap_llistxattr, - vfswrap_flistxattr, - vfswrap_removexattr, - vfswrap_lremovexattr, - vfswrap_fremovexattr, - vfswrap_setxattr, - vfswrap_lsetxattr, - vfswrap_fsetxattr - } -}; - -/**************************************************************************** - maintain the list of available backends -****************************************************************************/ - -static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name) -{ - struct vfs_init_function_entry *entry = backends; - - while(entry) { - if (strcmp(entry->name, name)==0) return entry; - entry = entry->next; - } - - return NULL; -} - -NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples) -{ - struct vfs_init_function_entry *entry = backends; - - if ((version != SMB_VFS_INTERFACE_VERSION)) { - DEBUG(0, ("Failed to register vfs module.\n" - "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n" - "current SMB_VFS_INTERFACE_VERSION is %d.\n" - "Please recompile against the current Samba Version!\n", - version, SMB_VFS_INTERFACE_VERSION)); - return NT_STATUS_OBJECT_TYPE_MISMATCH; - } - - if (!name || !name[0] || !vfs_op_tuples) { - DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (vfs_find_backend_entry(name)) { - DEBUG(0,("VFS module %s already loaded!\n", name)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - entry = smb_xmalloc(sizeof(struct vfs_init_function_entry)); - entry->name = smb_xstrdup(name); - entry->vfs_op_tuples = vfs_op_tuples; - - DLIST_ADD(backends, entry); - DEBUG(5, ("Successfully added vfs backend '%s'\n", name)); - return NT_STATUS_OK; -} - -/**************************************************************************** - initialise default vfs hooks -****************************************************************************/ - -static void vfs_init_default(connection_struct *conn) -{ - DEBUG(3, ("Initialising default vfs hooks\n")); - - memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops)); - memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops)); -} - -/**************************************************************************** - initialise custom vfs hooks - ****************************************************************************/ - -BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) -{ - vfs_op_tuple *ops; - char *module_name = NULL; - char *module_param = NULL, *p; - int i; - vfs_handle_struct *handle; - struct vfs_init_function_entry *entry; - - if (!conn||!vfs_object||!vfs_object[0]) { - DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n")); - return False; - } - - if(!backends) static_init_vfs; - - DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object)); - - module_name = smb_xstrdup(vfs_object); - - p = strchr(module_name, ':'); - - if (p) { - *p = 0; - module_param = p+1; - trim_char(module_param, ' ', ' '); - } - - trim_char(module_name, ' ', ' '); - - /* First, try to load the module with the new module system */ - if((entry = vfs_find_backend_entry(module_name)) || - (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && - (entry = vfs_find_backend_entry(module_name)))) { - - DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object)); - - if ((ops = entry->vfs_op_tuples) == NULL) { - DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object)); - SAFE_FREE(module_name); - return False; - } - } else { - DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object)); - SAFE_FREE(module_name); - return False; - } - - handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct)); - if (!handle) { - DEBUG(0,("talloc_zero() failed!\n")); - SAFE_FREE(module_name); - return False; - } - memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops)); - handle->conn = conn; - if (module_param) { - handle->param = talloc_strdup(conn->mem_ctx, module_param); - } - DLIST_ADD(conn->vfs_handles, handle); - - for(i=0; ops[i].op != NULL; i++) { - DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer)); - if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) { - /* Check whether this operation was already made opaque by different module */ - if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) { - /* No, it isn't overloaded yet. Overload. */ - DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object)); - ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op; - ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle; - } - } - /* Change current VFS disposition*/ - DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object)); - ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op; - ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle; - } - - SAFE_FREE(module_name); - return True; -} - -/***************************************************************** - Generic VFS init. -******************************************************************/ - -BOOL smbd_vfs_init(connection_struct *conn) -{ - const char **vfs_objects; - unsigned int i = 0; - int j = 0; - - /* Normal share - initialise with disk access functions */ - vfs_init_default(conn); - vfs_objects = lp_vfs_objects(SNUM(conn)); - - /* Override VFS functions if 'vfs object' was not specified*/ - if (!vfs_objects || !vfs_objects[0]) - return True; - - for (i=0; vfs_objects[i] ;) { - i++; - } - - for (j=i-1; j >= 0; j--) { - if (!vfs_init_custom(conn, vfs_objects[j])) { - DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j])); - return False; - } - } - return True; -} - -/******************************************************************* - Check if directory exists. -********************************************************************/ - -BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st) -{ - SMB_STRUCT_STAT st2; - BOOL ret; - - if (!st) - st = &st2; - - if (SMB_VFS_STAT(conn,dname,st) != 0) - return(False); - - ret = S_ISDIR(st->st_mode); - if(!ret) - errno = ENOTDIR; - - return ret; -} - -/******************************************************************* - vfs mkdir wrapper -********************************************************************/ - -int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode) -{ - int ret; - SMB_STRUCT_STAT sbuf; - - if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) { - - inherit_access_acl(conn, name, mode); - - /* - * Check if high bits should have been set, - * then (if bits are missing): add them. - * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir. - */ - if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && - !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode)) - SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode)); - } - return ret; -} - -/******************************************************************* - Check if an object exists in the vfs. -********************************************************************/ - -BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf) -{ - SMB_STRUCT_STAT st; - - if (!sbuf) - sbuf = &st; - - ZERO_STRUCTP(sbuf); - - if (SMB_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, const char *fname,SMB_STRUCT_STAT *sbuf) -{ - SMB_STRUCT_STAT st; - - if (!sbuf) - sbuf = &st; - - ZERO_STRUCTP(sbuf); - - if (SMB_VFS_STAT(conn,fname,sbuf) == -1) - return False; - return(S_ISREG(sbuf->st_mode)); -} - -/**************************************************************************** - Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data) -****************************************************************************/ - -ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) -{ - size_t total=0; - - while (total < byte_count) - { - ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total, - byte_count - total); - - if (ret == 0) return total; - if (ret == -1) { - if (errno == EINTR) - continue; - else - return -1; - } - total += ret; - } - return (ssize_t)total; -} - -ssize_t vfs_pread_data(files_struct *fsp, char *buf, - size_t byte_count, SMB_OFF_T offset) -{ - size_t total=0; - - while (total < byte_count) - { - ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total, - byte_count - total, offset + total); - - if (ret == 0) return total; - if (ret == -1) { - if (errno == EINTR) - continue; - else - return -1; - } - total += ret; - } - return (ssize_t)total; -} - -/**************************************************************************** - Write data to a fd on the vfs. -****************************************************************************/ - -ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N) -{ - size_t total=0; - ssize_t ret; - - while (total < N) { - ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total); - - if (ret == -1) - return -1; - if (ret == 0) - return total; - - total += ret; - } - return (ssize_t)total; -} - -ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer, - size_t N, SMB_OFF_T offset) -{ - size_t total=0; - ssize_t ret; - - while (total < N) { - ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total, - N - total, offset + total); - - if (ret == -1) - return -1; - if (ret == 0) - return total; - - total += ret; - } - return (ssize_t)total; -} -/**************************************************************************** - An allocate file space call using the vfs interface. - Allocates space for a file from a filedescriptor. - Returns 0 on success, -1 on failure. -****************************************************************************/ - -int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) -{ - int ret; - SMB_STRUCT_STAT st; - connection_struct *conn = fsp->conn; - SMB_BIG_UINT space_avail; - SMB_BIG_UINT bsize,dfree,dsize; - - release_level_2_oplocks_on_change(fsp); - - /* - * Actually try and commit the space on disk.... - */ - - DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len )); - - if (((SMB_OFF_T)len) < 0) { - DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name )); - return -1; - } - - ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st); - if (ret == -1) - return ret; - - if (len == (SMB_BIG_UINT)st.st_size) - return 0; - - if (len < (SMB_BIG_UINT)st.st_size) { - /* Shrink - use ftruncate. */ - - 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 = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) { - set_filelen_write_cache(fsp, len); - } - return ret; - } - - /* Grow - we need to test if we have enough space. */ - - if (!lp_strict_allocate(SNUM(fsp->conn))) - return 0; - - len -= st.st_size; - len /= 1024; /* Len is now number of 1k blocks needed. */ - space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); - - DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n", - fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail )); - - if (len > space_avail) { - errno = ENOSPC; - return -1; - } - - return 0; -} - -/**************************************************************************** - A vfs set_filelen call. - set the length of a file from a filedescriptor. - Returns 0 on success, -1 on failure. -****************************************************************************/ - -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 = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1) - set_filelen_write_cache(fsp, len); - - return ret; -} - -/**************************************************************************** - Transfer some data (n bytes) between two file_struct's. -****************************************************************************/ - -static files_struct *in_fsp; -static files_struct *out_fsp; - -static ssize_t read_fn(int fd, void *buf, size_t len) -{ - return SMB_VFS_READ(in_fsp, fd, buf, len); -} - -static ssize_t write_fn(int fd, const void *buf, size_t len) -{ - return SMB_VFS_WRITE(out_fsp, fd, buf, len); -} - -SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) -{ - in_fsp = in; - out_fsp = out; - - return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn); -} - -/******************************************************************* - A vfs_readdir wrapper which just returns the file name. -********************************************************************/ - -char *vfs_readdirname(connection_struct *conn, void *p) -{ - struct dirent *ptr= NULL; - char *dname; - - if (!p) - return(NULL); - - ptr = (struct dirent *)SMB_VFS_READDIR(conn,p); - if (!ptr) - return(NULL); - - dname = ptr->d_name; - -#ifdef NEXT2 - if (telldir(p) < 0) - return(NULL); -#endif - -#ifdef HAVE_BROKEN_READDIR - /* using /usr/ucb/cc is BAD */ - dname = dname - 2; -#endif - - return(dname); -} - -/******************************************************************* - A wrapper for vfs_chdir(). -********************************************************************/ - -int vfs_ChDir(connection_struct *conn, const char *path) -{ - int res; - static pstring LastDir=""; - - if (strcsequal(path,".")) - return(0); - - if (*path == '/' && strcsequal(LastDir,path)) - return(0); - - DEBUG(4,("vfs_ChDir to %s\n",path)); - - res = SMB_VFS_CHDIR(conn,path); - if (!res) - pstrcpy(LastDir,path); - return(res); -} - -/* number of list structures for a caching GetWd function. */ -#define MAX_GETWDCACHE (50) - -static struct { - SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ - SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ - char *dos_path; /* The pathname in DOS format. */ - BOOL valid; -} ino_list[MAX_GETWDCACHE]; - -extern BOOL use_getwd_cache; - -/**************************************************************************** - Prompte a ptr (to make it recently used) -****************************************************************************/ - -static void array_promote(char *array,int elsize,int element) -{ - char *p; - if (element == 0) - return; - - p = (char *)malloc(elsize); - - if (!p) { - DEBUG(5,("array_promote: malloc fail\n")); - return; - } - - memcpy(p,array + element * elsize, elsize); - memmove(array + elsize,array,elsize*element); - memcpy(array,p,elsize); - SAFE_FREE(p); -} - -/******************************************************************* - Return the absolute current directory path - given a UNIX pathname. - Note that this path is returned in DOS format, not UNIX - format. Note this can be called with conn == NULL. -********************************************************************/ - -char *vfs_GetWd(connection_struct *conn, char *path) -{ - pstring s; - static BOOL getwd_cache_init = False; - SMB_STRUCT_STAT st, st2; - int i; - - *s = 0; - - if (!use_getwd_cache) - return(SMB_VFS_GETWD(conn,path)); - - /* init the cache */ - if (!getwd_cache_init) { - getwd_cache_init = True; - for (i=0;i<MAX_GETWDCACHE;i++) { - string_set(&ino_list[i].dos_path,""); - ino_list[i].valid = False; - } - } - - /* Get the inode of the current directory, if this doesn't work we're - in trouble :-) */ - - if (SMB_VFS_STAT(conn, ".",&st) == -1) { - DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path)); - return(SMB_VFS_GETWD(conn,path)); - } - - - for (i=0; i<MAX_GETWDCACHE; i++) { - if (ino_list[i].valid) { - - /* If we have found an entry with a matching inode and dev number - then find the inode number for the directory in the cached string. - If this agrees with that returned by the stat for the current - directory then all is o.k. (but make sure it is a directory all - the same...) */ - - if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) { - if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) { - if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev && - (st2.st_mode & S_IFMT) == S_IFDIR) { - pstrcpy (path, ino_list[i].dos_path); - - /* promote it for future use */ - array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - return (path); - } else { - /* If the inode is different then something's changed, - scrub the entry and start from scratch. */ - ino_list[i].valid = False; - } - } - } - } - } - - /* We don't have the information to hand so rely on traditional methods. - The very slow getcwd, which spawns a process on some systems, or the - not quite so bad getwd. */ - - if (!SMB_VFS_GETWD(conn,s)) { - DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno))); - return (NULL); - } - - pstrcpy(path,s); - - DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev)); - - /* add it to the cache */ - i = MAX_GETWDCACHE - 1; - string_set(&ino_list[i].dos_path,s); - ino_list[i].dev = st.st_dev; - ino_list[i].inode = st.st_ino; - ino_list[i].valid = True; - - /* put it at the top of the list */ - array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - - return (path); -} - - -/* check if the file 'nmae' is a symlink, in that case check that it point to - a file that reside under the 'dir' tree */ - -static BOOL readlink_check(connection_struct *conn, const char *dir, char *name) -{ - BOOL ret = True; - pstring flink; - pstring cleanlink; - pstring savedir; - pstring realdir; - size_t reallen; - - if (!vfs_GetWd(conn, savedir)) { - DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir)); - return False; - } - - if (vfs_ChDir(conn, dir) != 0) { - DEBUG(0,("couldn't vfs_ChDir to %s\n", dir)); - return False; - } - - if (!vfs_GetWd(conn, realdir)) { - DEBUG(0,("couldn't vfs_GetWd for %s\n", dir)); - vfs_ChDir(conn, savedir); - return(False); - } - - reallen = strlen(realdir); - if (realdir[reallen -1] == '/') { - reallen--; - realdir[reallen] = 0; - } - - if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) { - DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name)); - if (*flink == '/') { - pstrcpy(cleanlink, flink); - } else { - pstrcpy(cleanlink, realdir); - pstrcat(cleanlink, "/"); - pstrcat(cleanlink, flink); - } - unix_clean_name(cleanlink); - - if (strncmp(cleanlink, realdir, reallen) != 0) { - DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen)); - ret = False; - } - } - - vfs_ChDir(conn, savedir); - - return ret; -} - -/******************************************************************* - Reduce a file name, removing .. elements and checking that - it is below dir in the heirachy. This uses vfs_GetWd() and so must be run - on the system that has the referenced file system. -********************************************************************/ - -BOOL reduce_name(connection_struct *conn, pstring s, const char *dir) -{ -#ifndef REDUCE_PATHS - return True; -#else - pstring dir2; - pstring wd; - pstring base_name; - pstring newname; - char *p=NULL; - BOOL relative = (*s != '/'); - - *dir2 = *wd = *base_name = *newname = 0; - - DEBUG(3,("reduce_name [%s] [%s]\n",s,dir)); - - /* We know there are no double slashes as this comes from srvstr_get_path(). - and has gone through check_path_syntax(). JRA */ - - pstrcpy(base_name,s); - p = strrchr_m(base_name,'/'); - - if (!p) - return readlink_check(conn, dir, s); - - if (!vfs_GetWd(conn,wd)) { - DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir)); - return(False); - } - - if (vfs_ChDir(conn,dir) != 0) { - DEBUG(0,("couldn't vfs_ChDir to %s\n",dir)); - return(False); - } - - if (!vfs_GetWd(conn,dir2)) { - DEBUG(0,("couldn't vfs_GetWd for %s\n",dir)); - vfs_ChDir(conn,wd); - return(False); - } - - if (p && (p != base_name)) { - *p = 0; - if (strcmp(p+1,".")==0) - p[1]=0; - if (strcmp(p+1,"..")==0) - *p = '/'; - } - - if (vfs_ChDir(conn,base_name) != 0) { - vfs_ChDir(conn,wd); - DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name)); - return(False); - } - - if (!vfs_GetWd(conn,newname)) { - vfs_ChDir(conn,wd); - DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name)); - return(False); - } - - if (p && (p != base_name)) { - pstrcat(newname,"/"); - pstrcat(newname,p+1); - } - - { - size_t l = strlen(dir2); - char *last_slash = strrchr_m(dir2, '/'); - - if (last_slash && (last_slash[1] == '\0')) - l--; - - if (strncmp(newname,dir2,l) != 0) { - vfs_ChDir(conn,wd); - DEBUG(2,("Bad access attempt: s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l)); - return(False); - } - - if (!readlink_check(conn, dir, newname)) { - DEBUG(2, ("Bad access attemt: %s is a symlink outside the share path", s)); - return(False); - } - - if (relative) { - if (newname[l] == '/') - pstrcpy(s,newname + l + 1); - else - pstrcpy(s,newname+l); - } else - pstrcpy(s,newname); - } - - vfs_ChDir(conn,wd); - - if (strlen(s) == 0) - pstrcpy(s,"./"); - - DEBUG(3,("reduced to %s\n",s)); - return(True); -#endif -} |