summaryrefslogtreecommitdiffstats
path: root/source/smbd
diff options
context:
space:
mode:
authorCVS Import User <samba-bugs@samba.org>2004-04-04 11:51:10 +0000
committerCVS Import User <samba-bugs@samba.org>2004-04-04 11:51:10 +0000
commite3d2dbdff6711b0bc768fb6b08f41240f21d5fba (patch)
tree159ef54b59b18e9b950f5c6af105915214244912 /source/smbd
parent139b1658ca30692835c1a7203c7cd003e587ac12 (diff)
downloadsamba-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')
-rw-r--r--source/smbd/.cvsignore1
-rw-r--r--source/smbd/blocking.c726
-rw-r--r--source/smbd/build_options.c535
-rw-r--r--source/smbd/change_trust_pw.c99
-rw-r--r--source/smbd/chgpasswd.c1054
-rw-r--r--source/smbd/close.c311
-rw-r--r--source/smbd/conn.c305
-rw-r--r--source/smbd/connection.c243
-rw-r--r--source/smbd/dfree.c164
-rw-r--r--source/smbd/dir.c1096
-rw-r--r--source/smbd/dosmode.c483
-rw-r--r--source/smbd/error.c137
-rw-r--r--source/smbd/fake_file.c166
-rw-r--r--source/smbd/fileio.c773
-rw-r--r--source/smbd/filename.c497
-rw-r--r--source/smbd/files.c449
-rw-r--r--source/smbd/ipc.c599
-rw-r--r--source/smbd/lanman.c3619
-rw-r--r--source/smbd/mangle.c124
-rw-r--r--source/smbd/mangle_hash.c783
-rw-r--r--source/smbd/mangle_hash2.c709
-rw-r--r--source/smbd/mangle_map.c212
-rw-r--r--source/smbd/message.c237
-rw-r--r--source/smbd/negprot.c550
-rw-r--r--source/smbd/noquotas.c38
-rw-r--r--source/smbd/notify.c225
-rw-r--r--source/smbd/notify_hash.c225
-rw-r--r--source/smbd/notify_kernel.c245
-rw-r--r--source/smbd/ntquotas.c262
-rw-r--r--source/smbd/nttrans.c2780
-rw-r--r--source/smbd/open.c1462
-rw-r--r--source/smbd/oplock.c1260
-rw-r--r--source/smbd/oplock_irix.c285
-rw-r--r--source/smbd/oplock_linux.c309
-rw-r--r--source/smbd/password.c551
-rw-r--r--source/smbd/pipes.c264
-rw-r--r--source/smbd/posix_acls.c3382
-rw-r--r--source/smbd/process.c1381
-rw-r--r--source/smbd/process_model.c115
-rw-r--r--source/smbd/process_model.h69
-rw-r--r--source/smbd/process_model.m427
-rw-r--r--source/smbd/process_single.c130
-rw-r--r--source/smbd/process_standard.c172
-rw-r--r--source/smbd/process_thread.c503
-rw-r--r--source/smbd/quotas.c1279
-rw-r--r--source/smbd/reply.c4974
-rw-r--r--source/smbd/rewrite.c82
-rw-r--r--source/smbd/sec_ctx.c449
-rw-r--r--source/smbd/server.c813
-rw-r--r--source/smbd/service.c838
-rw-r--r--source/smbd/session.c250
-rw-r--r--source/smbd/sesssetup.c938
-rw-r--r--source/smbd/srvstr.c44
-rw-r--r--source/smbd/statcache.c339
-rw-r--r--source/smbd/tdbutil.c85
-rw-r--r--source/smbd/trans2.c4165
-rw-r--r--source/smbd/uid.c430
-rw-r--r--source/smbd/utmp.c595
-rw-r--r--source/smbd/vfs-wrap.c1031
-rw-r--r--source/smbd/vfs.c951
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, &times)) {
- 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(&current_user, snum, jobid, &werr))
- errcode = NERR_Success;
- break;
- case 82: /* pause */
- if (print_job_pause(&current_user, snum, jobid, &werr))
- errcode = NERR_Success;
- break;
- case 83: /* resume */
- if (print_job_resume(&current_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(&current_user, snum, &werr)) errcode = NERR_Success;
- break;
- case 75: /* Resume queue */
- if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
- break;
- case 103: /* Purge */
- if (print_queue_purge(&current_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( &params[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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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(&current_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(&current_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(&current_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(&current_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(&current_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(&current_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( &current_ace->trustee, &current_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( &current_ace->trustee, &current_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, &current_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, &quotastat)) {
- 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 *) &quotabuf;
-
- 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 = &params[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, &quotas)!=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, &quotas)!=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, &params[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, &params[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, &params[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, &params[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( &params[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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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,
- &params, 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
-}