summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2005-09-30 17:13:37 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:04:48 -0500
commit54abd2aa66069e6baf7769c496f46d9dba18db39 (patch)
tree9cf8e88168011797319ba9e9866749201b1eac1e /source3/smbd
parent4a2cc231d22a82ed21771a72508f15d21ed63227 (diff)
downloadsamba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.gz
samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.bz2
samba-54abd2aa66069e6baf7769c496f46d9dba18db39.zip
r10656: BIG merge from trunk. Features not copied over
* \PIPE\unixinfo * winbindd's {group,alias}membership new functions * winbindd's lookupsids() functionality * swat (trunk changes to be reverted as per discussion with Deryck) (This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/blocking.c24
-rw-r--r--source3/smbd/change_trust_pw.c17
-rw-r--r--source3/smbd/chgpasswd.c4
-rw-r--r--source3/smbd/close.c87
-rw-r--r--source3/smbd/conn.c2
-rw-r--r--source3/smbd/connection.c8
-rw-r--r--source3/smbd/error.c23
-rw-r--r--source3/smbd/files.c33
-rw-r--r--source3/smbd/mangle_hash2.c4
-rw-r--r--source3/smbd/message.c11
-rw-r--r--source3/smbd/nttrans.c29
-rw-r--r--source3/smbd/open.c879
-rw-r--r--source3/smbd/oplock.c1331
-rw-r--r--source3/smbd/oplock_irix.c51
-rw-r--r--source3/smbd/oplock_linux.c56
-rw-r--r--source3/smbd/process.c457
-rw-r--r--source3/smbd/reply.c133
-rw-r--r--source3/smbd/server.c11
-rw-r--r--source3/smbd/sesssetup.c70
-rw-r--r--source3/smbd/trans2.c132
20 files changed, 1243 insertions, 2119 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 72d021d4e6..805e45f6ea 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -80,7 +80,8 @@ 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);
+static void received_unlock_msg(int msg_type, struct process_id src,
+ void *buf, size_t len);
/****************************************************************************
Function to push a blocking lock request onto the lock queue.
@@ -127,7 +128,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
/* 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,
+ lock_pid, procid_self(), blr->fsp->conn->cnum,
offset, count, PENDING_LOCK, &my_lock_ctx);
if (!NT_STATUS_IS_OK(status)) {
@@ -351,8 +352,8 @@ static BOOL process_lockread(blocking_lock_record *blr)
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 ) );
+ DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%lu nread=%ld\n",
+ fsp->fsp_name, fsp->fnum, (unsigned long)numtoread, (long)nread ) );
send_blocking_reply(outbuf,outsize);
return True;
@@ -526,7 +527,7 @@ void remove_pending_lock_requests_by_fid(files_struct *fsp)
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->lock_pid, procid_self(), blr->fsp->conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
@@ -552,7 +553,7 @@ 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->lock_pid, procid_self(), blr->fsp->conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
}
@@ -563,7 +564,8 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
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)
+static void received_unlock_msg(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
DEBUG(10,("received_unlock_msg\n"));
process_blocking_lock_queue(time(NULL));
@@ -641,7 +643,7 @@ void process_blocking_lock_queue(time_t t)
fsp->fnum, fsp->fsp_name ));
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, sys_getpid(), conn->cnum,
+ blr->lock_pid, procid_self(), conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
@@ -658,7 +660,7 @@ void process_blocking_lock_queue(time_t t)
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->lock_pid, procid_self(), conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
@@ -673,7 +675,7 @@ void process_blocking_lock_queue(time_t t)
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->lock_pid, procid_self(), conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
@@ -690,7 +692,7 @@ void process_blocking_lock_queue(time_t t)
if(blocking_lock_record_process(blr)) {
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- blr->lock_pid, sys_getpid(), conn->cnum,
+ blr->lock_pid, procid_self(), conn->cnum,
blr->offset, blr->count, True, NULL, NULL);
free_blocking_lock_record(blr);
diff --git a/source3/smbd/change_trust_pw.c b/source3/smbd/change_trust_pw.c
index 1178400e4d..738d12151d 100644
--- a/source3/smbd/change_trust_pw.c
+++ b/source3/smbd/change_trust_pw.c
@@ -33,7 +33,8 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct in_addr pdc_ip;
fstring dc_name;
- struct cli_state *cli;
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n",
domain));
@@ -71,20 +72,18 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m
* Now start the NT Domain stuff :-).
*/
- if(cli_nt_session_open(cli, PI_NETLOGON) == False) {
+ /* Shouldn't we open this with schannel ? JRA. */
+
+ netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, &nt_status);
+ if (!netlogon_pipe) {
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);
+ dc_name, nt_errstr(nt_status)));
cli_shutdown(cli);
- nt_status = NT_STATUS_UNSUCCESSFUL;
goto failed;
}
- nt_status = trust_pw_find_change_and_store_it(cli, cli->mem_ctx, domain);
+ nt_status = trust_pw_find_change_and_store_it(netlogon_pipe, cli->mem_ctx, domain);
- cli_nt_session_close(cli);
- cli_ulogoff(cli);
cli_shutdown(cli);
failed:
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index 374c57a083..c1168583ae 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -946,7 +946,7 @@ static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext)
int i;
uint32 pwHisLen, curr_pwHisLen;
- account_policy_get(AP_PASSWORD_HISTORY, &pwHisLen);
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
if (pwHisLen == 0) {
return False;
}
@@ -1017,7 +1017,7 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw
return NT_STATUS_ACCOUNT_RESTRICTION;
}
- if (account_policy_get(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
+ if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
DEBUG(1, ("user %s cannot change password - password too short\n",
username));
DEBUGADD(1, (" account policy min password len = %d\n", min_len));
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index afc645ca06..becca003b6 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -110,31 +110,30 @@ static int close_filestruct(files_struct *fsp)
If any deferred opens are waiting on this close, notify them.
****************************************************************************/
-static void notify_deferred_opens(files_struct *fsp)
+static void notify_deferred_opens(struct share_mode_lock *lck)
{
- deferred_open_entry *de_array = NULL;
- int num_de_entries, i;
- pid_t mypid = sys_getpid();
-
- if (!lp_defer_sharing_violations()) {
- return;
- }
-
- num_de_entries = get_deferred_opens(fsp->conn, fsp->dev, fsp->inode, &de_array);
- for (i = 0; i < num_de_entries; i++) {
- deferred_open_entry *entry = &de_array[i];
- if (entry->pid == mypid) {
- /*
- * We need to notify ourself to retry the open.
- * Do this by finding the queued SMB record, moving it
- * to the head of the queue and changing the wait time to zero.
- */
- schedule_sharing_violation_open_smb_message(entry->mid);
- } else {
- send_deferred_open_retry_message(entry);
- }
- }
- SAFE_FREE(de_array);
+ int i;
+
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+
+ if (!is_deferred_open_entry(e)) {
+ continue;
+ }
+
+ if (procid_is_me(&e->pid)) {
+ /*
+ * We need to notify ourself to retry the open. Do
+ * this by finding the queued SMB record, moving it to
+ * the head of the queue and changing the wait time to
+ * zero.
+ */
+ schedule_deferred_open_smb_message(e->op_mid);
+ } else {
+ message_send_pid(e->pid, MSG_SMB_OPEN_RETRY,
+ e, sizeof(*e), True);
+ }
+ }
}
/****************************************************************************
@@ -148,13 +147,12 @@ static void notify_deferred_opens(files_struct *fsp)
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_file = False;
connection_struct *conn = fsp->conn;
int saved_errno = 0;
int err = 0;
int err1 = 0;
+ struct share_mode_lock *lck;
remove_pending_lock_requests_by_fid(fsp);
@@ -194,23 +192,34 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
* This prevents race conditions with the file being created. JRA.
*/
- lock_share_entry_fsp(fsp);
-
- share_entry_count = del_share_mode(fsp, &share_entry,
- &delete_file);
+ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, fsp->fsp_name);
- DEBUG(10,("close_normal_file: share_entry_count = %lu for file %s\n",
- (unsigned long)share_entry_count, fsp->fsp_name ));
+ if (lck == NULL) {
+ DEBUG(0, ("Could not get share mode lock\n"));
+ return EINVAL;
+ }
- if (share_entry_count != 0) {
- /* We're not the last ones -- don't delete */
- delete_file = False;
+ if (!del_share_mode(lck, fsp)) {
+ DEBUG(0, ("Could not delete share entry\n"));
}
- SAFE_FREE(share_entry);
+ delete_file = lck->delete_on_close;
+
+ if (delete_file) {
+ int i;
+ /* See if others still have the file open. If this is the
+ * case, then don't delete */
+ for (i=0; i<lck->num_share_modes; i++) {
+ if (is_valid_share_mode_entry(&lck->share_modes[i])) {
+ delete_file = False;
+ break;
+ }
+ }
+ }
/* Notify any deferred opens waiting on this close. */
- notify_deferred_opens(fsp);
+ notify_deferred_opens(lck);
+ reply_to_oplock_break_requests(fsp);
/*
* NT can set delete_on_close of the last open
@@ -234,7 +243,7 @@ with error %s\n", fsp->fsp_name, strerror(errno) ));
process_pending_change_notify_queue((time_t)0);
}
- unlock_share_entry_fsp(fsp);
+ talloc_free(lck);
if(fsp->oplock_type)
release_file_oplock(fsp);
@@ -296,7 +305,7 @@ static int close_directory(files_struct *fsp, BOOL normal_close)
*/
if (normal_close &&
- get_delete_on_close_flag(fsp->dev, fsp->inode)) {
+ get_delete_on_close_flag(fsp->dev, fsp->inode, fsp->fsp_name)) {
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" ));
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index b69868ecec..bb000bac30 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -287,7 +287,7 @@ 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)
+void msg_force_tdis(int msg_type, struct process_id pid, void *buf, size_t len)
{
connection_struct *conn, *next;
fstring sharename;
diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c
index 32e2f058fc..07d3181144 100644
--- a/source3/smbd/connection.c
+++ b/source3/smbd/connection.c
@@ -38,7 +38,7 @@ TDB_CONTEXT *conn_tdb_ctx(void)
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->pid = procid_self();
pkey->cnum = conn?conn->cnum:-1;
fstrcpy(pkey->name, name);
#ifdef DEVELOPER
@@ -107,8 +107,8 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u
/* 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));
+ DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
+ procid_str_static(&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;
@@ -174,7 +174,7 @@ BOOL claim_connection(connection_struct *conn, const char *name,int max_connecti
/* fill in the crec */
ZERO_STRUCT(crec);
crec.magic = 0x280267;
- crec.pid = sys_getpid();
+ crec.pid = procid_self();
crec.cnum = conn?conn->cnum:-1;
if (conn) {
crec.uid = conn->uid;
diff --git a/source3/smbd/error.c b/source3/smbd/error.c
index 090a2f6d81..3cdcae5c7f 100644
--- a/source3/smbd/error.c
+++ b/source3/smbd/error.c
@@ -41,23 +41,22 @@ void set_saved_error_triple(int eclass, int ecode, NTSTATUS status)
override_ERR_ntstatus = status;
}
+void set_saved_ntstatus(NTSTATUS status)
+{
+ uint8 tmp_eclass; /* Hmmm. override_ERR_class is not uint8... */
+ override_ERR_ntstatus = status;
+ ntstatus_to_dos(status, &tmp_eclass, &override_ERR_code);
+ override_ERR_class = tmp_eclass;
+
+}
+
/****************************************************************************
Return the current settings of the error triple. Return True if any are set.
****************************************************************************/
-BOOL get_saved_error_triple(int *peclass, int *pecode, NTSTATUS *pstatus)
+NTSTATUS get_saved_ntstatus(void)
{
- if (peclass) {
- *peclass = override_ERR_class;
- }
- if (pecode) {
- *pecode = override_ERR_code;
- }
- if (pstatus) {
- *pstatus = override_ERR_ntstatus;
- }
-
- return (override_ERR_class || !NT_STATUS_IS_OK(override_ERR_ntstatus));
+ return override_ERR_ntstatus;
}
/****************************************************************************
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 65986e9612..181e17b11f 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -65,7 +65,7 @@ files_struct *file_new(connection_struct *conn)
{
int i;
static int first_file;
- files_struct *fsp, *next;
+ files_struct *fsp;
/* we want to give out file handles differently on each new
connection because of a common bug in MS clients where they try to
@@ -76,32 +76,21 @@ files_struct *file_new(connection_struct *conn)
first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
}
+ /* TODO: Port the id-tree implementation from Samba4 */
+
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"));
- set_saved_error_triple(ERRSRV, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES);
+ /* TODO: We have to unconditionally return a DOS error here,
+ * W2k3 even returns ERRDOS/ERRnofids for ntcreate&x with
+ * NTSTATUS negotiated */
+ set_saved_ntstatus(NT_STATUS_TOO_MANY_OPENED_FILES);
return NULL;
}
fsp = SMB_MALLOC_P(files_struct);
if (!fsp) {
- set_saved_error_triple(ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY);
+ set_saved_ntstatus(NT_STATUS_NO_MEMORY);
return NULL;
}
@@ -110,7 +99,7 @@ files_struct *file_new(connection_struct *conn)
fsp->fh = SMB_MALLOC_P(struct fd_handle);
if (!fsp->fh) {
SAFE_FREE(fsp);
- set_saved_error_triple(ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY);
+ set_saved_ntstatus(NT_STATUS_NO_MEMORY);
return NULL;
}
@@ -293,7 +282,9 @@ files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_i
DLIST_PROMOTE(Files, fsp);
}
/* Paranoia check. */
- if (fsp->fh->fd == -1 && fsp->oplock_type != NO_OPLOCK) {
+ if ((fsp->fh->fd == -1) &&
+ (fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_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,
diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c
index 613dda9a16..335ba8e2ef 100644
--- a/source3/smbd/mangle_hash2.c
+++ b/source3/smbd/mangle_hash2.c
@@ -212,7 +212,7 @@ 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));
+ M_DEBUG(10,("is_mangled_component %s (len %lu) ?\n", name, (unsigned long)len));
/* check the length */
if (len > 12 || len < 8)
@@ -250,7 +250,7 @@ static BOOL is_mangled_component(const char *name, size_t len)
}
}
- M_DEBUG(10,("is_mangled_component %s (len %u) -> yes\n", name, (unsigned int)len));
+ M_DEBUG(10,("is_mangled_component %s (len %lu) -> yes\n", name, (unsigned long)len));
return True;
}
diff --git a/source3/smbd/message.c b/source3/smbd/message.c
index 5af7d3e451..e975da3e15 100644
--- a/source3/smbd/message.c
+++ b/source3/smbd/message.c
@@ -43,6 +43,7 @@ static void msg_deliver(void)
int fd;
char *msg;
int len;
+ ssize_t sz;
if (! (*lp_msg_command()))
{
@@ -70,14 +71,20 @@ static void msg_deliver(void)
if (msgbuf[i] == '\r' && i < (msgpos-1) && msgbuf[i+1] == '\n') {
i++; continue;
}
- write(fd, &msgbuf[i++], 1);
+ sz = write(fd, &msgbuf[i++], 1);
+ if ( sz != 1 ) {
+ DEBUG(0,("Write error to fd %d: %ld(%d)\n",fd, (long)sz, errno ));
+ }
}
} else {
for (i = 0; i < len;) {
if (msg[i] == '\r' && i < (len-1) && msg[i+1] == '\n') {
i++; continue;
}
- write(fd, &msg[i++],1);
+ sz = write(fd, &msg[i++],1);
+ if ( sz != 1 ) {
+ DEBUG(0,("Write error to fd %d: %ld(%d)\n",fd, (long)sz, errno ));
+ }
}
SAFE_FREE(msg);
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index f9b70de0ac..3db55bad14 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -24,7 +24,6 @@
extern int max_send;
extern enum protocol_types Protocol;
extern int smb_read_error;
-extern int global_oplock_break;
extern struct current_user current_user;
static const char *known_nt_pipes[] = {
@@ -43,6 +42,7 @@ static const char *known_nt_pipes[] = {
"\\rpcecho",
"\\svcctl",
"\\eventlog",
+ "\\unixinfo",
NULL
};
@@ -861,7 +861,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n",
} else {
SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN);
}
- } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
} else {
SCVAL(p,0,NO_OPLOCK_RETURN);
@@ -1666,11 +1666,11 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
&info);
if (!fsp1) {
- get_saved_error_triple(NULL, NULL, &status);
+ status = get_saved_ntstatus();
if (NT_STATUS_IS_OK(status)) {
status = NT_STATUS_ACCESS_DENIED;
}
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
return status;
}
@@ -1684,11 +1684,11 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
&info);
if (!fsp2) {
- get_saved_error_triple(NULL, NULL, &status);
+ status = get_saved_ntstatus();
if (NT_STATUS_IS_OK(status)) {
status = NT_STATUS_ACCESS_DENIED;
}
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
close_file(fsp1,False);
return status;
}
@@ -1989,7 +1989,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, char *i
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size));
+ DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size));
SIVAL(params,0,(uint32)sd_size);
@@ -2743,21 +2743,6 @@ int reply_nttrans(connection_struct *conn,
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);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index ed847826d5..56d31c6940 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -24,11 +24,11 @@
extern struct current_user current_user;
extern userdom_struct current_user_info;
-extern uint16 global_oplock_port;
extern uint16 global_smbpid;
extern BOOL global_client_failed_oplock_break;
-struct dev_inode_bundle {
+struct deferred_open_record {
+ BOOL delayed_for_oplocks;
SMB_DEV_T dev;
SMB_INO_T inode;
};
@@ -208,7 +208,6 @@ static BOOL open_file(files_struct *fsp,
BOOL file_existed = VALID_STAT(*psbuf);
fsp->fh->fd = -1;
- fsp->oplock_type = NO_OPLOCK;
errno = EPERM;
/* Check permissions */
@@ -283,8 +282,7 @@ static BOOL open_file(files_struct *fsp,
/* Don't create files with Microsoft wildcard characters. */
if ((local_flags & O_CREAT) && !file_existed &&
ms_has_wild(fname)) {
- set_saved_error_triple(ERRDOS, ERRinvalidname,
- NT_STATUS_OBJECT_NAME_INVALID);
+ set_saved_ntstatus(NT_STATUS_OBJECT_NAME_INVALID);
return False;
}
@@ -354,7 +352,6 @@ static BOOL open_file(files_struct *fsp,
}
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;
@@ -397,7 +394,7 @@ static BOOL is_executable(const char *fname)
Returns True if conflict, False if not.
****************************************************************************/
-static BOOL share_conflict(share_mode_entry *entry,
+static BOOL share_conflict(struct share_mode_entry *entry,
uint32 access_mask,
uint32 share_access)
{
@@ -445,7 +442,6 @@ static BOOL share_conflict(share_mode_entry *entry,
DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
(unsigned int)(share) )); \
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); \
return True; \
}
#else
@@ -454,7 +450,6 @@ sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (u
DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
(unsigned int)(share) )); \
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); \
return True; \
}
#endif
@@ -480,11 +475,23 @@ sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (u
#if defined(DEVELOPER)
static void validate_my_share_entries(int num,
- share_mode_entry *share_entry)
+ struct share_mode_entry *share_entry)
{
files_struct *fsp;
- if (share_entry->pid != sys_getpid()) {
+ if (!procid_is_me(&share_entry->pid)) {
+ return;
+ }
+
+ if (is_deferred_open_entry(share_entry) &&
+ !open_was_deferred(share_entry->op_mid)) {
+ pstring str;
+ DEBUG(0, ("Got a deferred entry without a request: "
+ "PANIC: %s\n", share_mode_str(num, share_entry)));
+ smb_panic(str);
+ }
+
+ if (!is_valid_share_mode_entry(share_entry)) {
return;
}
@@ -497,7 +504,26 @@ static void validate_my_share_entries(int num,
"share entry with an open file\n");
}
+ if (is_deferred_open_entry(share_entry) ||
+ is_unused_share_mode_entry(share_entry)) {
+ goto panic;
+ }
+
+ if ((share_entry->op_type == NO_OPLOCK) &&
+ (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK)) {
+ /* Someone has already written to it, but I haven't yet
+ * noticed */
+ return;
+ }
+
if (((uint16)fsp->oplock_type) != share_entry->op_type) {
+ goto panic;
+ }
+
+ return;
+
+ panic:
+ {
pstring str;
DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
share_mode_str(num, share_entry) ));
@@ -510,375 +536,217 @@ static void validate_my_share_entries(int num,
}
#endif
-struct share_mode_entry_list {
- struct share_mode_entry_list *next, *prev;
- share_mode_entry entry;
-};
-
-static void free_broken_entry_list(struct share_mode_entry_list *broken_entry_list)
+static BOOL is_stat_open(uint32 access_mask)
{
- while (broken_entry_list) {
- struct share_mode_entry_list *broken_entry = broken_entry_list;
- DLIST_REMOVE(broken_entry_list, broken_entry);
- SAFE_FREE(broken_entry);
- }
-}
-
-static BOOL cause_oplock_break(int request, int existing, uint32 access_mask)
-{
- if ((access_mask == DELETE_ACCESS) &&
- (request == NO_OPLOCK)) {
- /* This is a delete request */
- return (BATCH_OPLOCK_TYPE(existing) != 0);
- }
-
- if (EXCLUSIVE_OPLOCK_TYPE(existing) && (request != NO_OPLOCK)) {
- return True;
- }
-
- if ((existing != NO_OPLOCK) && (request == NO_OPLOCK)) {
- return True;
- }
-
- return False;
+ return (access_mask &&
+ ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES))==0) &&
+ ((access_mask & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES)) != 0));
}
/****************************************************************************
- Deal with open deny mode and oplock break processing.
+ Deal with share modes
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 access_mask,
- uint32 share_access,
- uint32 create_options,
- int *p_oplock_request,
- BOOL *p_all_current_opens_are_level_II)
+static NTSTATUS open_mode_check(connection_struct *conn,
+ const char *fname,
+ struct share_mode_lock *lck,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options,
+ BOOL *file_existed)
{
int i;
- int num_share_modes;
- int oplock_contention_count = 0;
- share_mode_entry *old_shares = NULL;
- BOOL broke_oplock;
- BOOL delete_on_close;
- num_share_modes = get_share_modes(dev, inode, &old_shares, &delete_on_close);
-
- if(num_share_modes == 0) {
- SAFE_FREE(old_shares);
- return 0;
+ if(lck->num_share_modes == 0) {
+ return NT_STATUS_OK;
}
+
+ *file_existed = True;
- if (access_mask &&
- ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES|
- FILE_WRITE_ATTRIBUTES))==0) &&
- ((access_mask & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|
- FILE_WRITE_ATTRIBUTES)) != 0)) {
+ if (is_stat_open(access_mask)) {
/* Stat open that doesn't trigger oplock breaks or share mode
* checks... ! JRA. */
- SAFE_FREE(old_shares);
- return num_share_modes;
+ return NT_STATUS_OK;
}
/* A delete on close prohibits everything */
- if (delete_on_close) {
- SAFE_FREE(old_shares);
- errno = EACCES;
- return -1;
+ if (lck->delete_on_close) {
+ return NT_STATUS_DELETE_PENDING;
}
/*
* Check if the share modes will give us access.
*/
- do {
- struct share_mode_entry_list *broken_entry_list = NULL;
- struct share_mode_entry_list *broken_entry = NULL;
-
- 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];
- BOOL opb_ret;
-
#if defined(DEVELOPER)
- validate_my_share_entries(i, share_entry);
+ for(i = 0; i < lck->num_share_modes; i++) {
+ validate_my_share_entries(i, &lck->share_modes[i]);
+ }
#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 (!lp_share_modes(SNUM(conn))) {
+ return NT_STATUS_OK;
+ }
- if (!cause_oplock_break(*p_oplock_request,
- share_entry->op_type,
- access_mask)) {
- if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
- *p_all_current_opens_are_level_II = False;
- }
- continue;
- }
+ /* Now we check the share modes, after any oplock breaks. */
+ for(i = 0; i < lck->num_share_modes; i++) {
- /* This is an oplock break */
-
- 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);
-
- /* Now relock. */
- lock_share_entry(conn, dev, inode);
-
- if (!opb_ret) {
- 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);
- set_saved_error_triple(ERRDOS, ERRbadshare,
- NT_STATUS_SHARING_VIOLATION);
- return -1;
- }
-
- broken_entry = SMB_MALLOC_P(struct share_mode_entry_list);
- if (!broken_entry) {
- smb_panic("open_mode_check: malloc fail.\n");
- }
- broken_entry->entry = *share_entry;
- DLIST_ADD(broken_entry_list, broken_entry);
- broke_oplock = True;
-
- } /* end for */
-
- if (broke_oplock) {
- /* Update the current open table. */
- SAFE_FREE(old_shares);
- num_share_modes = get_share_modes(dev, inode,
- &old_shares,
- &delete_on_close);
+ if (!is_valid_share_mode_entry(&lck->share_modes[i])) {
+ continue;
}
- if (lp_share_modes(SNUM(conn))) {
- /* Now we check the share modes, after any oplock breaks. */
- for(i = 0; i < num_share_modes; i++) {
- share_mode_entry *share_entry = &old_shares[i];
-
- /* someone else has a share lock on it, check to see
- * if we can too */
- if (share_conflict(share_entry, access_mask,
- share_access)) {
- SAFE_FREE(old_shares);
- free_broken_entry_list(broken_entry_list);
- errno = EACCES;
- return -1;
- }
- }
+ /* someone else has a share lock on it, check to see if we can
+ * too */
+ if (share_conflict(&lck->share_modes[i],
+ access_mask, share_access)) {
+ return NT_STATUS_SHARING_VIOLATION;
}
-
- for(broken_entry = broken_entry_list; broken_entry;
- broken_entry = broken_entry->next) {
- 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->entry,
- share_entry) &&
- EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type))) {
- continue;
- }
-
- /*
- * 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->entry.pid, fname,
- (unsigned int)dev, (double)inode));
-
- if (process_exists(broken_entry->entry.pid)) {
- DEBUG(0,("open_mode_check: Existent process "
- "%lu left active oplock.\n",
- (unsigned long)broken_entry->entry.pid ));
- }
-
- if (del_share_entry(dev, inode, &broken_entry->entry,
- NULL, &delete_on_close) == -1) {
- free_broken_entry_list(broken_entry_list);
- errno = EACCES;
- set_saved_error_triple(ERRDOS, ERRbadshare,
- 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(dev, inode,
- &old_shares,
- &delete_on_close);
- break;
- } /* end for paranoia... */
- } /* end for broken_entry */
- free_broken_entry_list(broken_entry_list);
- } while(broke_oplock);
-
- /*
- * 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 ));
}
- SAFE_FREE(old_shares);
- return num_share_modes;
+ return NT_STATUS_OK;
}
-/****************************************************************************
- Delete the record for a handled deferred open entry.
-****************************************************************************/
+static BOOL is_delete_request(files_struct *fsp) {
+ return ((fsp->access_mask == DELETE_ACCESS) &&
+ (fsp->oplock_type == NO_OPLOCK));
+}
-static void delete_defered_open_entry_record(connection_struct *conn,
- SMB_DEV_T dev,
- SMB_INO_T inode)
+/*
+ * 1) No files open at all: Grant whatever the client wants.
+ *
+ * 2) Exclusive (or batch) oplock around: If the requested access is a delete
+ * request, break if the oplock around is a batch oplock. If it's another
+ * requested access type, break.
+ *
+ * 3) Only level2 around: Grant level2 and do nothing else.
+ */
+
+static BOOL delay_for_oplocks(struct share_mode_lock *lck, files_struct *fsp)
{
- uint16 mid = get_current_mid();
- pid_t mypid = sys_getpid();
- deferred_open_entry *de_array = NULL;
- int num_de_entries, i;
+ int i, num_level2;
+ struct share_mode_entry *exclusive = NULL;
+ BOOL delay_it = False;
+ BOOL have_level2 = False;
- if (!lp_defer_sharing_violations()) {
- return;
+ if (is_stat_open(fsp->access_mask)) {
+ fsp->oplock_type = NO_OPLOCK;
+ return False;
}
- num_de_entries = get_deferred_opens(conn, dev, inode, &de_array);
- for (i = 0; i < num_de_entries; i++) {
- deferred_open_entry *entry = &de_array[i];
- if (entry->pid == mypid && entry->mid == mid && entry->dev == dev &&
- entry->inode == inode) {
+ num_level2 = 0;
- /* Remove the deferred open entry from the array. */
- delete_deferred_open_entry(entry);
- SAFE_FREE(de_array);
- return;
+ if (lck->num_share_modes == 0) {
+ /* No files open at all: Directly grant whatever the client
+ * wants. */
+
+ if (fsp->oplock_type == NO_OPLOCK) {
+ /* Store a level2 oplock, but don't tell the client */
+ fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+ }
+ return False;
+ }
+
+ for (i=0; i<lck->num_share_modes; i++) {
+
+ if (!is_valid_share_mode_entry(&lck->share_modes[i])) {
+ continue;
+ }
+
+ if (EXCLUSIVE_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
+ SMB_ASSERT(exclusive == NULL);
+ exclusive = &lck->share_modes[i];
+ }
+
+ if (lck->share_modes[i].op_type == LEVEL_II_OPLOCK) {
+ have_level2 = True;
}
}
- SAFE_FREE(de_array);
+
+ if (exclusive != NULL) { /* Found an exclusive oplock */
+ SMB_ASSERT(!have_level2);
+ delay_it = is_delete_request(fsp) ?
+ BATCH_OPLOCK_TYPE(exclusive->op_type) : True;
+ }
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ /* We can at most grant level2 */
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ }
+
+ if ((fsp->oplock_type == NO_OPLOCK) && have_level2) {
+ /* Store a level2 oplock, but don't tell the client */
+ fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+ }
+
+ if (delay_it) {
+ DEBUG(10, ("Sending break request to PID %s\n",
+ procid_str_static(&exclusive->pid)));
+ exclusive->op_mid = get_current_mid();
+ if (!message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST,
+ exclusive, sizeof(*exclusive), True)) {
+ DEBUG(3, ("Could not send oplock break message\n"));
+ }
+ file_free(fsp);
+ }
+
+ return delay_it;
+}
+
+static BOOL request_timed_out(struct timeval request_time,
+ struct timeval timeout)
+{
+ struct timeval now, end_time;
+ GetTimeOfDay(&now);
+ end_time = timeval_sum(&request_time, &timeout);
+ return (timeval_compare(&end_time, &now) < 0);
}
/****************************************************************************
Handle the 1 second delay in returning a SHARING_VIOLATION error.
****************************************************************************/
-static void defer_open_sharing_error(connection_struct *conn,
- struct timeval *ptv,
- const char *fname,
- SMB_DEV_T dev,
- SMB_INO_T inode)
+static void defer_open(struct share_mode_lock *lck,
+ struct timeval request_time,
+ struct timeval timeout,
+ struct deferred_open_record *state)
{
uint16 mid = get_current_mid();
- pid_t mypid = sys_getpid();
- deferred_open_entry *de_array = NULL;
- int num_de_entries, i;
- struct dev_inode_bundle dib;
+ int i;
- if (!lp_defer_sharing_violations()) {
- return;
- }
+ /* Paranoia check */
- dib.dev = dev;
- dib.inode = inode;
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
- num_de_entries = get_deferred_opens(conn, dev, inode, &de_array);
- for (i = 0; i < num_de_entries; i++) {
- deferred_open_entry *entry = &de_array[i];
- if (entry->pid == mypid && entry->mid == mid) {
- /*
- * Check if a 1 second timeout has expired.
- */
- if (usec_time_diff(ptv, &entry->time) >
- SHARING_VIOLATION_USEC_WAIT) {
- DEBUG(10,("defer_open_sharing_error: Deleting "
- "deferred open entry for mid %u, "
- "file %s\n",
- (unsigned int)mid, fname ));
-
- /* Expired, return a real error. */
- /* Remove the deferred open entry from the array. */
-
- delete_deferred_open_entry(entry);
- SAFE_FREE(de_array);
- return;
- }
- /*
- * If the timeout hasn't expired yet and we still have
- * a sharing violation, just leave the entry in the
- * deferred open array alone. We do need to reschedule
- * this open call though (with the original created
- * time).
- */
- DEBUG(10,("defer_open_sharing_error: time [%u.%06u] "
- "updating deferred open entry for mid %u, file %s\n",
- (unsigned int)entry->time.tv_sec,
- (unsigned int)entry->time.tv_usec,
- (unsigned int)mid, fname ));
-
- push_sharing_violation_open_smb_message(&entry->time,
- (char *)&dib,
- sizeof(dib));
- SAFE_FREE(de_array);
- return;
+ if (!is_deferred_open_entry(e)) {
+ continue;
+ }
+
+ if (procid_is_me(&e->pid) && (e->op_mid == mid)) {
+ DEBUG(0, ("Trying to defer an already deferred "
+ "request: mid=%d, exiting\n", mid));
+ exit_server("exiting");
}
}
+ /* End paranoia check */
+
DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
- "open entry for mid %u, file %s\n",
- (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec,
- (unsigned int)mid, fname ));
+ "open entry for mid %u\n",
+ (unsigned int)request_time.tv_sec,
+ (unsigned int)request_time.tv_usec,
+ (unsigned int)mid));
- if (!push_sharing_violation_open_smb_message(ptv, (char *)&dib, sizeof(dib))) {
- SAFE_FREE(de_array);
- return;
- }
- if (!add_deferred_open(mid, ptv, dev, inode, global_oplock_port, fname)) {
- remove_sharing_violation_open_smb_message(mid);
+ if (!push_deferred_smb_message(mid, request_time, timeout,
+ (char *)state, sizeof(*state))) {
+ exit_server("push_deferred_smb_message failed\n");
}
+ add_deferred_open(lck, mid, request_time, state->dev, state->inode);
/*
* Push the MID of this packet on the signing queue.
@@ -888,8 +756,6 @@ static void defer_open_sharing_error(connection_struct *conn,
*/
srv_defer_sign_response(mid);
-
- SAFE_FREE(de_array);
}
/****************************************************************************
@@ -1196,8 +1062,6 @@ files_struct *open_file_ntcreate(connection_struct *conn,
BOOL internal_only_open = 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;
mode_t new_unx_mode = (mode_t)0;
@@ -1205,8 +1069,11 @@ files_struct *open_file_ntcreate(connection_struct *conn,
int info;
uint32 existing_dos_attributes = 0;
struct pending_message_list *pml = NULL;
- uint16 port = 0;
uint16 mid = get_current_mid();
+ BOOL delayed_for_oplocks = False;
+ struct timeval request_time = timeval_zero();
+ struct share_mode_lock *lck = NULL;
+ NTSTATUS status;
if (conn->printer) {
/*
@@ -1241,9 +1108,11 @@ files_struct *open_file_ntcreate(connection_struct *conn,
}
if ((pml = get_open_deferred_message(mid)) != NULL) {
- struct dev_inode_bundle dib;
+ struct deferred_open_record *state =
+ (struct deferred_open_record *)pml->private_data.data;
- memcpy(&dib, pml->private_data.data, sizeof(dib));
+ request_time = pml->request_time;
+ delayed_for_oplocks = state->delayed_for_oplocks;
/* There could be a race condition where the dev/inode pair
has changed since we deferred the message. If so, just
@@ -1255,24 +1124,18 @@ files_struct *open_file_ntcreate(connection_struct *conn,
notified of a close and we don't want to trigger another
spurious oplock break. */
- if (!file_existed || dib.dev != psbuf->st_dev ||
- dib.inode != psbuf->st_ino || pml->msg_time.tv_sec ||
- pml->msg_time.tv_usec) {
- /* Ensure we don't reprocess this message. */
- remove_sharing_violation_open_smb_message(mid);
-
- /* Now remove the deferred open entry under lock. */
- lock_share_entry(conn, dib.dev, dib.inode);
- delete_defered_open_entry_record(conn, dib.dev,
- dib.inode);
- unlock_share_entry(conn, dib.dev, dib.inode);
-
- set_saved_error_triple(ERRDOS, ERRbadshare,
- NT_STATUS_SHARING_VIOLATION);
- return NULL;
+ /* Now remove the deferred open entry under lock. */
+ lck = get_share_mode_lock(NULL, state->dev, state->inode,
+ fname);
+ if (lck == NULL) {
+ DEBUG(0, ("could not get share mode lock\n"));
+ } else {
+ del_deferred_open_entry(lck, mid);
+ talloc_destroy(lck);
}
+
/* Ensure we don't reprocess this message. */
- remove_sharing_violation_open_smb_message(mid);
+ remove_deferred_open_smb_message(mid);
}
if (!check_name(fname,conn)) {
@@ -1285,7 +1148,8 @@ files_struct *open_file_ntcreate(connection_struct *conn,
}
/* ignore any oplock requests if oplocks are disabled */
- if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break) {
+ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break ||
+ IS_VETO_OPLOCK_PATH(conn, fname)) {
oplock_request = 0;
}
@@ -1325,7 +1189,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
DEBUG(5,("open_file_ntcreate: FILE_OPEN "
"requested for file %s and file "
"doesn't exist.\n", fname ));
- set_saved_error_triple(ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ set_saved_ntstatus(NT_STATUS_OBJECT_NAME_NOT_FOUND);
errno = ENOENT;
return NULL;
}
@@ -1338,7 +1202,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE "
"requested for file %s and file "
"doesn't exist.\n", fname ));
- set_saved_error_triple(ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ set_saved_ntstatus(NT_STATUS_OBJECT_NAME_NOT_FOUND);
errno = ENOENT;
return NULL;
}
@@ -1369,8 +1233,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
break;
default:
- set_saved_error_triple(ERRDOS, ERRinvalidparam,
- NT_STATUS_INVALID_PARAMETER);
+ set_saved_ntstatus(NT_STATUS_INVALID_PARAMETER);
return NULL;
}
@@ -1447,8 +1310,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
DEBUG(5,("open_file_ntcreate: write access requested for "
"file %s on read only %s\n",
fname, !CAN_WRITE(conn) ? "share" : "file" ));
- set_saved_error_triple(ERRDOS, ERRnoaccess,
- NT_STATUS_ACCESS_DENIED);
+ set_saved_ntstatus(NT_STATUS_ACCESS_DENIED);
errno = EACCES;
return NULL;
}
@@ -1458,45 +1320,96 @@ files_struct *open_file_ntcreate(connection_struct *conn,
return NULL;
}
+ fsp->dev = psbuf->st_dev;
+ fsp->inode = psbuf->st_ino;
+ fsp->share_access = share_access;
+ fsp->fh->private_options = create_options;
+ fsp->access_mask = access_mask;
+ fsp->oplock_type = oplock_request;
+
+ if (timeval_is_zero(&request_time)) {
+ request_time = fsp->open_time;
+ }
+
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,
- access_mask, share_access,
- create_options,
- &oplock_request,
- &all_current_opens_are_level_II);
- if(num_share_modes == -1) {
-
- if (!internal_only_open) {
- NTSTATUS status;
- get_saved_error_triple(NULL, NULL, &status);
- if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) {
- /* Check if this can be done with the
- * deny_dos and fcb calls. */
- if (create_options &
- (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
- NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
- files_struct *fsp_dup;
- fsp_dup = fcb_or_dos_open(conn, fname, dev,
- inode, access_mask,
- share_access,
- create_options);
-
- if (fsp_dup) {
- unlock_share_entry(conn, dev, inode);
- file_free(fsp);
- if (pinfo) {
- *pinfo = FILE_WAS_OPENED;
- }
- conn->num_files_open++;
- return fsp_dup;
- }
+ lck = get_share_mode_lock(NULL, dev, inode, fname);
+
+ if (lck == NULL) {
+ DEBUG(0, ("Could not get share mode lock\n"));
+ set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
+ return NULL;
+ }
+
+ if (delay_for_oplocks(lck, fsp)) {
+ struct deferred_open_record state;
+ struct timeval timeout;
+
+ if (delayed_for_oplocks) {
+ DEBUG(0, ("Trying to delay for oplocks "
+ "twice\n"));
+ exit_server("exiting");
+ }
+
+ timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+
+ /* Normally the smbd we asked should respond within
+ * OPLOCK_BREAK_TIMEOUT seconds regardless of whether
+ * the client did, give twice the timeout as a safety
+ * measure here in case the other smbd is stuck
+ * somewhere else. */
+
+ state.delayed_for_oplocks = True;
+ state.dev = dev;
+ state.inode = inode;
+
+ if (!request_timed_out(request_time, timeout)) {
+ defer_open(lck, request_time, timeout,
+ &state);
+ }
+
+ talloc_free(lck);
+ return NULL;
+ }
+
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &file_existed);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
+ /* DELETE_PENDING is not deferred for a second */
+ set_saved_ntstatus(status);
+ talloc_free(lck);
+ file_free(fsp);
+ return NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+
+ SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
+
+ /* Check if this can be done with the deny_dos and fcb
+ * calls. */
+ if (create_options &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+ files_struct *fsp_dup;
+ fsp_dup = fcb_or_dos_open(conn, fname, dev,
+ inode, access_mask,
+ share_access,
+ create_options);
+
+ if (fsp_dup) {
+ talloc_free(lck);
+ file_free(fsp);
+ if (pinfo) {
+ *pinfo = FILE_WAS_OPENED;
}
+ conn->num_files_open++;
+ return fsp_dup;
}
}
@@ -1527,8 +1440,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
if (!fsp_open && errno) {
/* Default error. */
- set_saved_error_triple(ERRDOS, ERRnoaccess,
- NT_STATUS_ACCESS_DENIED);
+ set_saved_ntstatus(NT_STATUS_ACCESS_DENIED);
}
/*
@@ -1536,27 +1448,32 @@ files_struct *open_file_ntcreate(connection_struct *conn,
* cope with the braindead 1 second delay.
*/
- if (!internal_only_open) {
- NTSTATUS status;
- get_saved_error_triple(NULL, NULL, &status);
- if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) {
- /* The fsp->open_time here represents
- * the current time of day. */
- defer_open_sharing_error(conn,
- &fsp->open_time,
- fname, dev, inode);
+ if (!internal_only_open &&
+ lp_defer_sharing_violations()) {
+ struct timeval timeout;
+ struct deferred_open_record state;
+
+ timeout = timeval_set(0, SHARING_VIOLATION_USEC_WAIT);
+
+ state.delayed_for_oplocks = False;
+ state.dev = dev;
+ state.inode = inode;
+
+ if (!request_timed_out(request_time,
+ timeout)) {
+ defer_open(lck, request_time, timeout,
+ &state);
}
}
- unlock_share_entry(conn, dev, inode);
+ talloc_free(lck);
if (fsp_open) {
fd_close(conn, fsp);
/*
* We have detected a sharing violation here
* so return the correct error code
*/
- set_saved_error_triple(ERRDOS, ERRbadshare,
- NT_STATUS_SHARING_VIOLATION);
+ set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
}
file_free(fsp);
return NULL;
@@ -1567,23 +1484,28 @@ files_struct *open_file_ntcreate(connection_struct *conn,
*/
}
+ SMB_ASSERT(!file_existed || (lck != NULL));
+
/*
* 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)))) {
+ (def_acl = directory_has_default_acl(conn,
+ parent_dirname(fname)))) {
unx_mode = 0777;
}
DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
- (unsigned int)flags,(unsigned int)flags2,(unsigned int)unx_mode));
+ (unsigned int)flags, (unsigned int)flags2,
+ (unsigned int)unx_mode));
/*
* open_file strips any O_TRUNC flags itself.
*/
- fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode,access_mask);
+ fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode,
+ access_mask);
if (!fsp_open && (flags2 & O_EXCL) && (errno == EEXIST)) {
/*
@@ -1602,23 +1524,24 @@ files_struct *open_file_ntcreate(connection_struct *conn,
}
if (!fsp_open) {
- if(file_existed) {
- unlock_share_entry(conn, dev, inode);
+ if (lck != NULL) {
+ talloc_free(lck);
}
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) {
/*
+ * 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.
+ */
+
+ /*
* 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
@@ -1628,70 +1551,41 @@ files_struct *open_file_ntcreate(connection_struct *conn,
dev = fsp->dev;
inode = fsp->inode;
- lock_share_entry_fsp(fsp);
-
- num_share_modes = open_mode_check(conn, fname, dev, inode,
- access_mask, share_access,
- create_options,
- &oplock_request,
- &all_current_opens_are_level_II);
-
- if(num_share_modes == -1) {
- NTSTATUS status;
- get_saved_error_triple(NULL, NULL, &status);
- if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) {
- /* Check if this can be done with the deny_dos
- * and fcb calls. */
- if (create_options &
- (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
- NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
- files_struct *fsp_dup;
- fsp_dup = fcb_or_dos_open(conn, fname, dev, inode,
- access_mask, share_access,
- create_options);
- if (fsp_dup) {
- unlock_share_entry(conn, dev, inode);
- fd_close(conn, fsp);
- file_free(fsp);
- if (pinfo) {
- *pinfo = FILE_WAS_OPENED;
- }
- conn->num_files_open++;
- return fsp_dup;
- }
- }
-
- /*
- * If we're returning a share violation,
- * ensure we cope with the braindead 1 second
- * delay.
- */
-
- /* The fsp->open_time here represents the
- * current time of day. */
- defer_open_sharing_error(conn, &fsp->open_time,
- fname, dev, inode);
- }
+ lck = get_share_mode_lock(NULL, dev, inode, fname);
- unlock_share_entry_fsp(fsp);
- fd_close(conn,fsp);
+ if (lck == NULL) {
+ DEBUG(0, ("Coult not get share mode lock\n"));
+ fd_close(conn, fsp);
file_free(fsp);
- /*
- * We have detected a sharing violation here, so
- * return the correct code.
- */
- set_saved_error_triple(ERRDOS, ERRbadshare,
- NT_STATUS_SHARING_VIOLATION);
+ set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
return NULL;
}
- /*
- * If there are any share modes set then the file *did*
- * exist. Ensure we return the correct value for action.
- */
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &file_existed);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ struct deferred_open_record state;
- if (num_share_modes > 0) {
- file_existed = True;
+ fd_close(conn, fsp);
+ file_free(fsp);
+
+ state.delayed_for_oplocks = False;
+ state.dev = dev;
+ state.inode = inode;
+
+ /* Do it all over again immediately. In the second
+ * round we will find that the file existed and handle
+ * the DELETE_PENDING and FCB cases correctly. No need
+ * to duplicate the code here. Essentially this is a
+ * "goto top of this function", but don't tell
+ * anybody... */
+
+ defer_open(lck, request_time, timeval_zero(),
+ &state);
+ talloc_free(lck);
+ return NULL;
}
/*
@@ -1699,6 +1593,8 @@ files_struct *open_file_ntcreate(connection_struct *conn,
*/
}
+ SMB_ASSERT(lck != NULL);
+
/* 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
@@ -1725,7 +1621,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
*/
if ((SMB_VFS_FTRUNCATE(fsp,fsp->fh->fd,0) == -1) ||
(SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf)==-1)) {
- unlock_share_entry_fsp(fsp);
+ talloc_free(lck);
fd_close(conn,fsp);
file_free(fsp);
return NULL;
@@ -1761,20 +1657,14 @@ files_struct *open_file_ntcreate(connection_struct *conn,
* 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;
+ if ((fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
+ if (!set_file_oplock(fsp, fsp->oplock_type)) {
+ /* Could not get the kernel oplock */
+ fsp->oplock_type = NO_OPLOCK;
+ }
}
-
- set_share_mode(fsp, port, oplock_request);
+ set_share_mode(lck, fsp, 0, fsp->oplock_type);
if (create_options & FILE_DELETE_ON_CLOSE) {
uint32 dosattr= existing_dos_attributes;
@@ -1788,19 +1678,16 @@ files_struct *open_file_ntcreate(connection_struct *conn,
result = can_set_delete_on_close(fsp, True, dosattr);
if (!NT_STATUS_IS_OK(result)) {
- uint8 u_e_c;
- uint32 u_e_code;
- BOOL dummy_del_on_close;
/* Remember to delete the mode we just added. */
- del_share_mode(fsp, NULL, &dummy_del_on_close);
- unlock_share_entry_fsp(fsp);
+ del_share_mode(lck, fsp);
+ talloc_free(lck);
fd_close(conn,fsp);
file_free(fsp);
- ntstatus_to_dos(result, &u_e_c, &u_e_code);
- set_saved_error_triple(u_e_c, u_e_code, result);
+ set_saved_ntstatus(result);
return NULL;
}
- set_delete_on_close(fsp, True);
+ lck->delete_on_close = True;
+ lck->modified = True;
}
if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
@@ -1860,8 +1747,8 @@ files_struct *open_file_ntcreate(connection_struct *conn,
/* If this is a successful open, we must remove any deferred open
* records. */
- delete_defered_open_entry_record(conn, fsp->dev, fsp->inode);
- unlock_share_entry_fsp(fsp);
+ del_deferred_open_entry(lck, mid);
+ talloc_free(lck);
conn->num_files_open++;
@@ -1945,17 +1832,13 @@ files_struct *open_directory(connection_struct *conn,
if (is_ntfs_stream_name(fname)) {
DEBUG(0,("open_directory: %s is a stream name!\n", fname ));
- /* NB. Is the DOS error ERRbadpath or ERRbaddirectory ? */
- set_saved_error_triple(ERRDOS, ERRbadpath,
- NT_STATUS_NOT_A_DIRECTORY);
+ set_saved_ntstatus(NT_STATUS_NOT_A_DIRECTORY);
return NULL;
}
if (dir_existed && !S_ISDIR(psbuf->st_mode)) {
DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
- /* NB. Is the DOS error ERRbadpath or ERRbaddirectory ? */
- set_saved_error_triple(ERRDOS, ERRbadpath,
- NT_STATUS_NOT_A_DIRECTORY);
+ set_saved_ntstatus(NT_STATUS_NOT_A_DIRECTORY);
return NULL;
}
@@ -1967,8 +1850,7 @@ files_struct *open_directory(connection_struct *conn,
DEBUG(5,("open_directory: FILE_OPEN requested "
"for directory %s and it doesn't "
"exist.\n", fname ));
- set_saved_error_triple(ERRDOS, ERRbadfile,
- NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ set_saved_ntstatus(NT_STATUS_OBJECT_NAME_NOT_FOUND);
return NULL;
}
info = FILE_WAS_OPENED;
@@ -2008,8 +1890,7 @@ files_struct *open_directory(connection_struct *conn,
"0x%x for directory %s\n",
(unsigned int)create_disposition, fname));
file_free(fsp);
- set_saved_error_triple(ERRDOS, ERRinvalidparam,
- NT_STATUS_INVALID_PARAMETER);
+ set_saved_ntstatus(NT_STATUS_INVALID_PARAMETER);
return NULL;
}
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index c0c9e989a9..385f998b1c 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -3,6 +3,7 @@
oplock processing
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Jeremy Allison 1998 - 2001
+ Copyright (C) Volker Lendecke 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,25 +22,17 @@
#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 struct timeval smb_last_time;
extern uint32 global_client_caps;
-extern struct current_user current_user;
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.
****************************************************************************/
@@ -58,9 +51,6 @@ 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;
}
@@ -75,13 +65,9 @@ BOOL oplock_message_waiting(fd_set *fds)
****************************************************************************/
-BOOL receive_local_message( char *buffer, int buffer_len, int timeout)
+void process_kernel_oplocks(void)
{
- 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;
@@ -92,110 +78,29 @@ BOOL receive_local_message( char *buffer, int buffer_len, int timeout)
* already been eaten. JRA.
*/
- if (koplocks && koplocks->msg_waiting(&fds)) {
- return koplocks->receive_message(&fds, buffer, buffer_len);
+ if (!koplocks) {
+ return;
}
- 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);
+ while (koplocks->msg_waiting(&fds)) {
+ files_struct *fsp;
+ struct kernel_oplock_message msg;
- 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);
- }
+ fsp = koplocks->receive_message(&fds);
- /*
- * 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;
+ if (fsp == NULL) {
+ DEBUG(3, ("Kernel oplock message announced, but none "
+ "received\n"));
+ return;
}
- /* 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);
+ msg.dev = fsp->dev;
+ msg.inode = fsp->inode;
+ msg.file_id = fsp->file_id;
+ message_send_pid(pid_to_procid(sys_getpid()),
+ MSG_SMB_KERNEL_BREAK,
+ &msg, sizeof(msg), True);
}
-
- 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;
}
/****************************************************************************
@@ -229,13 +134,19 @@ tv_sec = %x, tv_usec = %x\n",
void release_file_oplock(files_struct *fsp)
{
- if ((fsp->oplock_type != NO_OPLOCK) && koplocks)
+ if ((fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
+ koplocks) {
koplocks->release_oplock(fsp);
+ }
if (fsp->oplock_type == LEVEL_II_OPLOCK)
level_II_oplocks_open--;
- else if (fsp->oplock_type)
+ else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
exclusive_oplocks_open--;
+
+ SMB_ASSERT(exclusive_oplocks_open>=0);
+ SMB_ASSERT(level_II_oplocks_open>=0);
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
@@ -263,45 +174,58 @@ static void downgrade_file_oplock(files_struct *fsp)
to none even if a "break-to-level II" was sent.
****************************************************************************/
-BOOL remove_oplock(files_struct *fsp, BOOL break_to_none)
+BOOL remove_oplock(files_struct *fsp)
{
SMB_DEV_T dev = fsp->dev;
SMB_INO_T inode = fsp->inode;
- BOOL ret = True;
+ BOOL ret;
+ struct share_mode_lock *lck;
/* 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 ));
+ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL);
+ if (lck == NULL) {
+ DEBUG(0,("remove_oplock: failed to lock share entry for "
+ "file %s\n", fsp->fsp_name ));
return False;
}
+ ret = remove_share_oplock(lck, fsp);
+ if (!ret) {
+ 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));
+ }
+ release_file_oplock(fsp);
+ talloc_free(lck);
+ return ret;
+}
- if (fsp->sent_oplock_break == BREAK_TO_NONE_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;
- }
+/*
+ * Deal with a reply when a break-to-level II was sent.
+ */
+BOOL downgrade_oplock(files_struct *fsp)
+{
+ SMB_DEV_T dev = fsp->dev;
+ SMB_INO_T inode = fsp->inode;
+ BOOL ret;
+ struct share_mode_lock *lck;
- 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);
+ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL);
+ if (lck == NULL) {
+ DEBUG(0,("downgrade_oplock: failed to lock share entry for "
+ "file %s\n", fsp->fsp_name ));
+ return False;
}
-
- unlock_share_entry_fsp(fsp);
+ ret = downgrade_share_oplock(lck, fsp);
+ if (!ret) {
+ DEBUG(0,("downgrade_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));
+ }
+
+ downgrade_file_oplock(fsp);
+ talloc_free(lck);
return ret;
}
@@ -313,12 +237,7 @@ dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)
int setup_oplock_select_set( fd_set *fds)
{
- int maxfd = oplock_sock;
-
- if(oplock_sock == -1)
- return 0;
-
- FD_SET(oplock_sock,fds);
+ int maxfd = 0;
if (koplocks && koplocks->notification_fd != -1) {
FD_SET(koplocks->notification_fd, fds);
@@ -329,197 +248,31 @@ int setup_oplock_select_set( fd_set *fds)
}
/****************************************************************************
- Process an oplock break message - whether it came from the UDP socket
- or from the kernel.
+ Set up an oplock break message.
****************************************************************************/
-BOOL process_local_message(char *buffer, int buf_size)
+static char *new_break_smb_message(TALLOC_CTX *mem_ctx,
+ files_struct *fsp, uint8_t cmd)
{
- 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;
- struct sockaddr_in toaddr;
-
- 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"));
- return False;
- }
- 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;
-
- case RETRY_DEFERRED_OPEN_CMD:
-
- /* Request to retry and open that would return SHARING_VIOLATION. */
- if (msg_len != DEFERRED_OPEN_MSG_LEN) {
- DEBUG(0,("process_local_message: incorrect length for RETRY_DEFERRED_OPEN_CMD (was %d, should be %d).\n",
- (int)msg_len, (int)DEFERRED_OPEN_MSG_LEN));
- return False;
- }
- {
- uint16 mid;
-
- memcpy((char *)&remotepid, msg_start+DEFERRED_OPEN_PID_OFFSET,sizeof(remotepid));
- memcpy((char *)&inode, msg_start+DEFERRED_OPEN_INODE_OFFSET,sizeof(inode));
- memcpy((char *)&dev, msg_start+DEFERRED_OPEN_DEV_OFFSET,sizeof(dev));
- memcpy((char *)&mid, msg_start+DEFERRED_OPEN_MID_OFFSET,sizeof(mid));
-
- DEBUG(5,("process_local_message: RETRY_DEFERRED_OPEN from \
-pid %d, port %d, dev = %x, inode = %.0f, mid = %u\n",
- (int)remotepid, from_port, (unsigned int)dev, (double)inode, (unsigned int)mid));
-
- schedule_sharing_violation_open_smb_message(mid);
- }
- return True;
-
- /*
- * 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));
+ char *result = TALLOC_ARRAY(mem_ctx, char, smb_size + 8*2 + 0);
- 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 == 0) &&
- (level_II_oplocks_open == 0)) {
- /*
- * 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"));
-
- } else {
- if (!oplock_break(dev, inode, file_id, False)) {
- DEBUG(0,("process_local_message: oplock break failed.\n"));
- return False;
- }
- }
-
- /*
- * 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))) {
- return True;
- }
-
- /* 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;
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
}
- 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);
+ memset(result,'\0',smb_size);
+ set_message(result,8,0,True);
+ SCVAL(result,smb_com,SMBlockingX);
+ SSVAL(result,smb_tid,fsp->conn->cnum);
+ SSVAL(result,smb_pid,0xFFFF);
+ SSVAL(result,smb_uid,0);
+ SSVAL(result,smb_mid,0xFFFF);
+ SCVAL(result,smb_vwv0,0xFF);
+ SSVAL(result,smb_vwv2,fsp->fnum);
+ SCVAL(result,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+ SCVAL(result,smb_vwv3+1,cmd);
+ return result;
}
/****************************************************************************
@@ -602,639 +355,266 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, un
return fsp;
}
-/****************************************************************************
- Process a level II oplock break directly.
- We must call this function with the share mode entry locked.
-****************************************************************************/
-
-static BOOL oplock_break_level2(files_struct *fsp, BOOL local_request)
+static void oplock_timeout_handler(struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
{
- char outbuf[128];
- 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) {
- BOOL sign_state;
-
- /*
- * 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.
- */
-
- if (local_request) {
- wait_before_sending_break();
- }
-
- /* Prepare the SMBlockingX message. */
- prepare_break_message( outbuf, fsp, False);
-
- /* Save the server smb signing state. */
- sign_state = srv_oplock_set_signing(False);
-
- show_msg(outbuf);
- if (!send_smb(smbd_server_fd(), outbuf))
- exit_server("oplock_break_level2: send_smb failed.");
+ files_struct *fsp = private_data;
- /* Restore the sign state to what it was. */
- srv_oplock_set_signing(sign_state);
- }
-
- /*
- * Now we must update the shared memory structure to tell
- * everyone else we no longer have a level II oplock on
- * this open file. We must call this function with the share mode
- * entry locked so we can change the entry directly.
- */
-
- 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(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;
+ DEBUG(0, ("Oplock break failed -- replying anyway\n"));
+ global_client_failed_oplock_break = True;
+ remove_oplock(fsp);
+ reply_to_oplock_break_requests(fsp);
}
-/****************************************************************************
- Process an oplock break directly.
- This is always called with the share mode lock *NOT* held.
-****************************************************************************/
-
-static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local_request)
+static void process_oplock_break_message(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
- char *inbuf = NULL;
- char *saved_inbuf = NULL;
- char *outbuf = NULL;
- char *saved_outbuf = NULL;
- files_struct *fsp = NULL;
- time_t start_time;
- BOOL shutdown_server = False;
- BOOL oplock_timeout = False;
+ struct share_mode_entry *msg = buf;
+ files_struct *fsp;
+ char *break_msg;
+ BOOL break_to_level2 = 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)) {
- BOOL ret;
- /* We must always call oplock_break_level2() with
- the share mode entry locked. */
- if (lock_share_entry_fsp(fsp) == False) {
- DEBUG(0,("oplock_break: unable to lock share entry for file %s\n", fsp->fsp_name ));
- return False;
- }
- ret = oplock_break_level2(fsp, local_request);
- unlock_share_entry_fsp(fsp);
- return ret;
+ if (buf == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
}
- /* 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 (len != sizeof(*msg)) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+ return;
}
- if(global_oplock_break) {
- DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n"));
- abort();
- }
+ DEBUG(10, ("Got oplock break message from pid %d: %d/%d/%d\n",
+ (int)procid_to_pid(&src), (int)msg->dev, (int)msg->inode,
+ (int)msg->share_file_id));
- /*
- * 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.
- */
+ fsp = initial_break_processing(msg->dev, msg->inode,
+ msg->share_file_id);
- if((inbuf = NewInBuffer(&saved_inbuf))==NULL) {
- DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
- return False;
+ if (fsp == NULL) {
+ /* We hit race here. Break messages are sent, and before we
+ * get to process this message, we have closed the file. Reply
+ * with 'ok, oplock broken' */
+ DEBUG(3, ("Did not find fsp\n"));
+ message_send_pid(src, MSG_SMB_BREAK_RESPONSE,
+ msg, sizeof(*msg), True);
+ return;
}
- if((outbuf = NewOutBuffer(&saved_outbuf))==NULL) {
- DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
- /* Free must be done before set.. */
- free_InBuffer(inbuf);
- set_InBuffer(saved_inbuf);
- return False;
+ if (fsp->sent_oplock_break != NO_BREAK_SENT) {
+ /* Remember we have to inform the requesting PID when the
+ * client replies */
+ msg->pid = src;
+ ADD_TO_ARRAY(NULL, struct share_mode_entry, *msg,
+ &fsp->pending_break_messages,
+ &fsp->num_pending_break_messages);
+ return;
}
- /*
- * 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.
- */
-
- if (local_request) {
- wait_before_sending_break();
+ if (EXCLUSIVE_OPLOCK_TYPE(msg->op_type) &&
+ !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(3, ("Already downgraded oplock on %.0f/%.0f: %s\n",
+ (double)fsp->dev, (double)fsp->inode,
+ fsp->fsp_name));
+ message_send_pid(src, MSG_SMB_BREAK_RESPONSE,
+ msg, sizeof(*msg), True);
+ return;
}
- /* Prepare the SMBlockingX message. */
+ if ((msg_type == MSG_SMB_BREAK_REQUEST) &&
+ (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))) {
+ break_to_level2 = True;
+ }
- 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;
+ break_msg = new_break_smb_message(NULL, fsp, break_to_level2 ?
+ OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
+ if (break_msg == NULL) {
+ exit_server("Could not talloc break_msg\n");
}
- 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:BREAK_TO_NONE_SENT;
+ /* Need to wait before sending a break message to a file of our own */
+ if (procid_to_pid(&src) == sys_getpid()) {
+ wait_before_sending_break();
+ }
/* Save the server smb signing state. */
sign_state = srv_oplock_set_signing(False);
- show_msg(outbuf);
- if (!send_smb(smbd_server_fd(), outbuf)) {
- srv_oplock_set_signing(sign_state);
+ show_msg(break_msg);
+ if (!send_smb(smbd_server_fd(), break_msg)) {
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);
+ talloc_free(break_msg);
- /*
- * 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;
- /*
- * Initialize saved_dir to something sensible: vfs_GetWd may not work well
- * for root: the directory may be NFS-mounted and exported with root_squash
- * (so has no root access).
- */
- pstrcpy(saved_dir,saved_fsp_conn->connectpath);
- vfs_GetWd(saved_fsp_conn,saved_dir);
- /* Save the chain fnum. */
- file_chain_save();
-
- pstrcpy(file_name, fsp->fsp_name);
-
- change_to_root_user();
-
- /*
- * 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. With async I/O, write calls may steal the global InBuffer,
- * so ensure we're using the correct one each time around the loop.
- */
-
- while((fsp = initial_break_processing(dev, inode, file_id)) &&
- OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-
- inbuf = get_InBuffer();
- outbuf = get_OutBuffer();
-
- 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));
+ if (msg_type == MSG_SMB_BREAK_REQUEST) {
+ fsp->sent_oplock_break = break_to_level2 ?
+ LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
+ } else {
+ /* Async level2 request, don't send a reply */
+ fsp->sent_oplock_break = ASYNC_LEVEL_II_BREAK_SENT;
+ }
+ msg->pid = src;
+ ADD_TO_ARRAY(NULL, struct share_mode_entry, *msg,
+ &fsp->pending_break_messages,
+ &fsp->num_pending_break_messages);
- break;
- }
+ if (fsp->oplock_timeout != NULL) {
+ DEBUG(0, ("Logic problem -- have an oplock event hanging "
+ "around\n"));
+ }
- /*
- * 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.
- */
+ fsp->oplock_timeout =
+ add_timed_event(NULL,
+ timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
+ "oplock_timeout_handler",
+ oplock_timeout_handler, fsp);
- process_smb(inbuf, outbuf);
+ if (fsp->oplock_timeout == NULL) {
+ DEBUG(0, ("Could not add oplock timeout handler\n"));
+ }
+}
- /*
- * Die if we go over the time limit.
- */
+static void process_kernel_oplock_break(int msg_type, struct process_id src,
+ void *buf, size_t len)
+{
+ struct kernel_oplock_message *msg = buf;
+ files_struct *fsp;
+ char *break_msg;
+ BOOL sign_state;
- 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;
- }
+ if (buf == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
}
- /*
- * 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");
+ if (len != sizeof(*msg)) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+ return;
}
- /* Including the directory. */
- vfs_ChDir(saved_fsp_conn,saved_dir);
-
- /* Restore the chain fnum. */
- file_chain_restore();
+ DEBUG(10, ("Got kernel oplock break message from pid %d: %d/%d/%d\n",
+ (int)procid_to_pid(&src), (int)msg->dev, (int)msg->inode,
+ (int)msg->file_id));
- /* Free the buffers we've been using to recurse. */
- /* Free must be done before set.. */
- free_InBuffer(inbuf);
- free_OutBuffer(outbuf);
+ fsp = initial_break_processing(msg->dev, msg->inode, msg->file_id);
- /* Restore the global In/Out buffers. */
- set_InBuffer(saved_inbuf);
- set_OutBuffer(saved_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 (fsp == NULL) {
+ DEBUG(3, ("Got a kernel oplock break message for a file "
+ "I don't know about\n"));
+ return;
}
- /*
- * 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");
+ if (fsp->sent_oplock_break != NO_BREAK_SENT) {
+ /* This is ok, kernel oplocks come in completely async */
+ DEBUG(3, ("Got a kernel oplock request while waiting for a "
+ "break reply\n"));
+ return;
}
- /* 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();
+ break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE);
+ if (break_msg == NULL) {
+ exit_server("Could not talloc break_msg\n");
}
- /* We know we have no saved errors here. */
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
- 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 );
+ show_msg(break_msg);
+ if (!send_smb(smbd_server_fd(), break_msg)) {
+ exit_server("oplock_break: send_smb failed.");
}
- 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.
- This function is called with no share locks held.
-****************************************************************************/
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
-BOOL request_oplock_break(share_mode_entry *share_entry)
-{
- char op_break_msg[OPLOCK_BREAK_MSG_LEN];
- struct sockaddr_in addr_out;
- pid_t pid = sys_getpid();
- time_t start_time;
- int time_left;
- 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;
- }
+ talloc_free(break_msg);
- DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+ fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
+}
-#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... */
+void reply_to_oplock_break_requests(files_struct *fsp)
+{
+ int i;
- /* Call oplock break direct. */
- return oplock_break(dev, inode, file_id, True);
+ for (i=0; i<fsp->num_pending_break_messages; i++) {
+ struct share_mode_entry *msg = &fsp->pending_break_messages[i];
+ message_send_pid(msg->pid, MSG_SMB_BREAK_RESPONSE,
+ msg, sizeof(*msg), 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 = LEVEL_II_OPLOCK_BREAK_CMD;
- } else {
- break_cmd_type = OPLOCK_BREAK_CMD;
+ SAFE_FREE(fsp->pending_break_messages);
+ fsp->num_pending_break_messages = 0;
+ if (fsp->oplock_timeout != NULL) {
+ talloc_free(fsp->oplock_timeout);
+ fsp->oplock_timeout = NULL;
}
+ return;
+}
- 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 synchronous oplock break message to " );
- dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
- (unsigned int)dev, (double)inode, file_id );
- }
+static void process_oplock_break_response(int msg_type, struct process_id src,
+ void *buf, size_t len)
+{
+ struct share_mode_entry *msg = buf;
- 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 (buf == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
}
- /*
- * 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);
+ if (len != sizeof(*msg)) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+ return;
}
- DEBUG(3,("request_oplock_break: broke oplock.\n"));
+ DEBUG(10, ("Got oplock break response from pid %d: %d/%d/%d mid %d\n",
+ (int)procid_to_pid(&src), (int)msg->dev, (int)msg->inode,
+ (int)msg->share_file_id, (int)msg->op_mid));
- return True;
+ /* Here's the hack from open.c, store the mid in the 'port' field */
+ schedule_deferred_open_smb_message(msg->op_mid);
}
-/****************************************************************************
- 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)
+static void process_open_retry_message(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
- 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->fh->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;
- }
+ struct share_mode_entry *msg = buf;
+
+ if (buf == NULL) {
+ DEBUG(0, ("Got NULL buffer\n"));
+ return;
}
- return False;
-}
-
-/****************************************************************************
- Send an asynchronous oplock break message to another smbd process.
-****************************************************************************/
-
-static BOOL request_remote_level2_async_oplock_break(share_mode_entry *share_entry)
-{
- char op_break_msg[OPLOCK_BREAK_MSG_LEN];
- struct sockaddr_in addr_out;
- pid_t pid = sys_getpid();
- SMB_DEV_T dev = share_entry->dev;
- SMB_INO_T inode = share_entry->inode;
- unsigned long file_id = share_entry->share_file_id;
-
- /* We need to send a ASYNC_LEVEL_II_OPLOCK_BREAK_CMD message to the port in the share mode entry. */
-
- SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,ASYNC_LEVEL_II_OPLOCK_BREAK_CMD);
- memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
- memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
- memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
- memcpy(op_break_msg+OPLOCK_BREAK_FILEID_OFFSET,(char *)&file_id,sizeof(file_id));
-
- /* Set the address and port. */
- memset((char *)&addr_out,'\0',sizeof(addr_out));
- addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr_out.sin_port = htons( share_entry->op_port );
- addr_out.sin_family = AF_INET;
-
- if( DEBUGLVL( 3 ) ) {
- dbgtext( "request_remote_level2_async_oplock_break: sending an asynchronous oplock break message to ");
- dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
- (unsigned int)dev, (double)inode, file_id );
+ if (len != sizeof(*msg)) {
+ DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+ return;
}
- 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_remote_level2_async_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;
- }
+ DEBUG(10, ("Got open retry msg from pid %d: %d/%d mid %d\n",
+ (int)procid_to_pid(&src), (int)msg->dev, (int)msg->inode,
+ (int)msg->op_mid));
- DEBUG(3,("request_remote_level2_async_oplock_break: sent async break message to level II entry.\n"));
- return True;
+ schedule_deferred_open_smb_message(msg->op_mid);
}
/****************************************************************************
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.
+ 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 num_share_modes = 0;
int i;
- BOOL dummy;
+ struct share_mode_lock *lck;
/*
* If this file is level II oplocked then we need
@@ -1247,125 +627,71 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
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 ));
+ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL);
+ if (lck == NULL) {
+ 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->dev, fsp->inode, &share_list,
- &dummy);
-
DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n",
- num_share_modes ));
+ lck->num_share_modes ));
+
+ if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
+ /* See if someone else has already downgraded us, then we
+ don't have to do anything */
+ for (i=0; i<lck->num_share_modes; i++) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if ((e->op_type == NO_OPLOCK) &&
+ (e->share_file_id == fsp->file_id) &&
+ (e->dev == fsp->dev) &&
+ (e->inode == fsp->inode) &&
+ (procid_is_me(&e->pid))) {
+ /* We're done */
+ fsp->oplock_type = NO_OPLOCK;
+ talloc_free(lck);
+ return;
+ }
+ }
+ }
- for(i = 0; i < num_share_modes; i++) {
- share_mode_entry *share_entry = &share_list[i];
+ for(i = 0; i < lck->num_share_modes; i++) {
+ struct share_mode_entry *share_entry = &lck->share_modes[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.
+ * 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 ));
+ 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)
+ if ((share_entry->op_type == NO_OPLOCK) ||
+ (share_entry->op_type == FAKE_LEVEL_II_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);
+ DEBUG(0,("release_level_2_oplocks_on_change: PANIC. "
+ "share mode entry %d is an exlusive "
+ "oplock !\n", i ));
+ talloc_free(lck);
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);
-
- } 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_remote_level2_async_oplock_break(share_entry);
- }
- }
-
- 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");
- }
-}
-
-/****************************************************************************
- Send a 'retry your open' message to a process with a deferred open entry.
-****************************************************************************/
-
-BOOL send_deferred_open_retry_message(deferred_open_entry *entry)
-{
- char de_msg[DEFERRED_OPEN_MSG_LEN];
- struct sockaddr_in addr_out;
- pid_t pid = sys_getpid();
-
- memset(de_msg, '\0', DEFERRED_OPEN_MSG_LEN);
- SSVAL(de_msg,DEFERRED_OPEN_CMD_OFFSET,RETRY_DEFERRED_OPEN_CMD);
- memcpy(de_msg+DEFERRED_OPEN_PID_OFFSET,(char *)&pid,sizeof(pid));
- memcpy(de_msg+DEFERRED_OPEN_DEV_OFFSET,(char *)&entry->dev,sizeof(entry->dev));
- memcpy(de_msg+DEFERRED_OPEN_INODE_OFFSET,(char *)&entry->inode,sizeof(entry->inode));
- memcpy(de_msg+DEFERRED_OPEN_MID_OFFSET,(char *)&entry->mid,sizeof(entry->mid));
-
- /* 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( entry->port );
- addr_out.sin_family = AF_INET;
-
- if( DEBUGLVL( 3 ) ) {
- dbgtext( "send_deferred_open_retry_message: sending a message to ");
- dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port );
- dbgtext( "for dev = %x, inode = %.0f, mid = %u\n",
- (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid );
+ message_send_pid(share_entry->pid, MSG_SMB_ASYNC_LEVEL2_BREAK,
+ share_entry, sizeof(*share_entry), True);
}
- if(sys_sendto(oplock_sock,de_msg,DEFERRED_OPEN_MSG_LEN,0,
- (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
- if( DEBUGLVL( 0 ) ) {
- dbgtext( "send_deferred_open_retry_message: failed sending a message to ");
- dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port );
- dbgtext( "for dev = %x, inode = %.0f, mid = %u\n",
- (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid );
- dbgtext( "Error was %s\n", strerror(errno) );
- }
- return False;
- }
- return True;
+ remove_all_share_oplocks(lck, fsp);
+ talloc_free(lck);
}
/****************************************************************************
@@ -1374,30 +700,18 @@ BOOL send_deferred_open_retry_message(deferred_open_entry *entry)
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);
+ message_register(MSG_SMB_BREAK_REQUEST,
+ process_oplock_break_message);
+ message_register(MSG_SMB_ASYNC_LEVEL2_BREAK,
+ process_oplock_break_message);
+ message_register(MSG_SMB_BREAK_RESPONSE,
+ process_oplock_break_response);
+ message_register(MSG_SMB_KERNEL_BREAK,
+ process_kernel_oplock_break);
+ message_register(MSG_SMB_OPEN_RETRY,
+ process_open_retry_message);
if (lp_kernel_oplocks()) {
#if HAVE_KERNEL_OPLOCKS_IRIX
@@ -1407,8 +721,5 @@ address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno)));
#endif
}
- DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",
- (int)sys_getpid(), global_oplock_port));
-
return True;
}
diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c
index f4405a021e..f49aa297e4 100644
--- a/source3/smbd/oplock_irix.c
+++ b/source3/smbd/oplock_irix.c
@@ -86,7 +86,7 @@ Disabling kernel oplock support.\n", strerror(errno) ));
* oplock break protocol.
****************************************************************************/
-static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
+static files_struct *irix_oplock_receive_message(fd_set *fds)
{
extern int smb_read_error;
oplock_stat_t os;
@@ -102,7 +102,7 @@ static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_le
DEBUG(0,("irix_oplock_receive_message: read of kernel notification failed. \
Error was %s.\n", strerror(errno) ));
smb_read_error = READ_ERROR;
- return False;
+ return NULL;
}
/*
@@ -122,7 +122,7 @@ Error was %s.\n", strerror(errno) ));
return True;
}
smb_read_error = READ_ERROR;
- return False;
+ return NULL;
}
/*
@@ -138,24 +138,8 @@ Error was %s.\n", strerror(errno) ));
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;
+
+ return fsp;
}
/****************************************************************************
@@ -215,30 +199,6 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
}
/****************************************************************************
- 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.
****************************************************************************/
@@ -274,7 +234,6 @@ struct kernel_oplocks *irix_init_kernel_oplocks(void)
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;
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index 477832c6e8..ab0c08f7fc 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -128,10 +128,10 @@ static int linux_setlease(int fd, int leasetype)
* oplock break protocol.
****************************************************************************/
-static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
+static files_struct *linux_oplock_receive_message(fd_set *fds)
{
int fd;
- struct files_struct *fsp;
+ files_struct *fsp;
BlockSignals(True, RT_SIGNAL_LEASE);
fd = fd_pending_array[0];
@@ -145,32 +145,7 @@ static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_l
/* 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;
+ return fsp;
}
/****************************************************************************
@@ -224,30 +199,6 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
}
/****************************************************************************
- 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.
****************************************************************************/
@@ -299,7 +250,6 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
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;
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 8f9cc52882..0b7b94cce2 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
process incoming packets - main loop
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Volker Lendecke 2005
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
@@ -44,12 +45,11 @@ int max_send = BUFFER_SIZE;
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 BOOL global_machine_password_needs_changing;
extern int max_send;
/****************************************************************************
@@ -66,106 +66,72 @@ uint16 get_current_mid(void)
for processing.
****************************************************************************/
-static struct pending_message_list *smb_oplock_queue;
-static struct pending_message_list *smb_sharing_violation_queue;
-
-enum q_type { OPLOCK_QUEUE, SHARE_VIOLATION_QUEUE };
-
-/****************************************************************************
- Free up a message.
-****************************************************************************/
-
-static void free_queued_message(struct pending_message_list *msg)
-{
- data_blob_free(&msg->buf);
- data_blob_free(&msg->private_data);
- SAFE_FREE(msg);
-}
+static struct pending_message_list *deferred_open_queue;
/****************************************************************************
Function to push a message onto the tail of a linked list of smb messages ready
for processing.
****************************************************************************/
-static BOOL push_queued_message(enum q_type qt, char *buf, int msg_len, struct timeval *ptv, char *private_data, size_t private_len)
+static BOOL push_queued_message(char *buf, int msg_len,
+ struct timeval request_time,
+ struct timeval end_time,
+ char *private_data, size_t private_len)
{
struct pending_message_list *tmp_msg;
- struct pending_message_list *msg = SMB_MALLOC_P(struct pending_message_list);
+ struct pending_message_list *msg;
+
+ msg = TALLOC_ZERO_P(NULL, struct pending_message_list);
if(msg == NULL) {
DEBUG(0,("push_message: malloc fail (1)\n"));
return False;
}
- memset(msg,'\0',sizeof(*msg));
-
- msg->buf = data_blob(buf, msg_len);
+ msg->buf = data_blob_talloc(msg, buf, msg_len);
if(msg->buf.data == NULL) {
DEBUG(0,("push_message: malloc fail (2)\n"));
- SAFE_FREE(msg);
+ talloc_free(msg);
return False;
}
- if (ptv) {
- msg->msg_time = *ptv;
- }
+ msg->request_time = request_time;
+ msg->end_time = end_time;
if (private_data) {
- msg->private_data = data_blob(private_data, private_len);
+ msg->private_data = data_blob_talloc(msg, private_data,
+ private_len);
if (msg->private_data.data == NULL) {
DEBUG(0,("push_message: malloc fail (3)\n"));
- data_blob_free(&msg->buf);
- SAFE_FREE(msg);
+ talloc_free(msg);
return False;
}
}
- if (qt == OPLOCK_QUEUE) {
- DLIST_ADD_END(smb_oplock_queue, msg, tmp_msg);
- } else {
- DLIST_ADD_END(smb_sharing_violation_queue, msg, tmp_msg);
- }
+ DLIST_ADD_END(deferred_open_queue, msg, tmp_msg);
- DEBUG(10,("push_message: pushed message length %u on queue %s\n",
- (unsigned int)msg_len,
- qt == OPLOCK_QUEUE ? "smb_oplock_queue" : "smb_sharing_violation_queue" ));
+ DEBUG(10,("push_message: pushed message length %u on "
+ "deferred_open_queue\n", (unsigned int)msg_len));
return True;
}
/****************************************************************************
- Function to push an oplock smb message onto a linked list of local smb messages ready
- for processing.
-****************************************************************************/
-
-BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
-{
- BOOL ret = push_queued_message(OPLOCK_QUEUE, buf, msg_len, NULL, NULL, 0);
- if (ret) {
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(SVAL(buf,smb_mid));
- }
- return ret;
-}
-
-/****************************************************************************
Function to delete a sharing violation open message by mid.
****************************************************************************/
-void remove_sharing_violation_open_smb_message(uint16 mid)
+void remove_deferred_open_smb_message(uint16 mid)
{
struct pending_message_list *pml;
- if (!lp_defer_sharing_violations()) {
- return;
- }
-
- for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
if (mid == SVAL(pml->buf.data,smb_mid)) {
- DEBUG(10,("remove_sharing_violation_open_smb_message: deleting mid %u len %u\n",
- (unsigned int)mid, (unsigned int)pml->buf.length ));
- DLIST_REMOVE(smb_sharing_violation_queue, pml);
- free_queued_message(pml);
+ DEBUG(10,("remove_sharing_violation_open_smb_message: "
+ "deleting mid %u len %u\n",
+ (unsigned int)mid,
+ (unsigned int)pml->buf.length ));
+ DLIST_REMOVE(deferred_open_queue, pml);
+ talloc_free(pml);
return;
}
}
@@ -176,30 +142,26 @@ void remove_sharing_violation_open_smb_message(uint16 mid)
schedule it for immediate processing.
****************************************************************************/
-void schedule_sharing_violation_open_smb_message(uint16 mid)
+void schedule_deferred_open_smb_message(uint16 mid)
{
struct pending_message_list *pml;
int i = 0;
- if (!lp_defer_sharing_violations()) {
- return;
- }
-
- for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
- DEBUG(10,("schedule_sharing_violation_open_smb_message: [%d] msg_mid = %u\n", i++,
+ DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
(unsigned int)msg_mid ));
if (mid == msg_mid) {
- DEBUG(10,("schedule_sharing_violation_open_smb_message: scheduling mid %u\n",
+ DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
mid ));
- pml->msg_time.tv_sec = 0;
- pml->msg_time.tv_usec = 0;
- DLIST_PROMOTE(smb_sharing_violation_queue, pml);
+ pml->end_time.tv_sec = 0;
+ pml->end_time.tv_usec = 0;
+ DLIST_PROMOTE(deferred_open_queue, pml);
return;
}
}
- DEBUG(10,("schedule_sharing_violation_open_smb_message: failed to find message mid %u\n",
+ DEBUG(10,("schedule_deferred_open_smb_message: failed to find message mid %u\n",
mid ));
}
@@ -211,13 +173,9 @@ BOOL open_was_deferred(uint16 mid)
{
struct pending_message_list *pml;
- if (!lp_defer_sharing_violations()) {
- return False;
- }
-
- for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
if (SVAL(pml->buf.data,smb_mid) == mid) {
- set_saved_error_triple(SMB_SUCCESS, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
return True;
}
}
@@ -232,11 +190,7 @@ struct pending_message_list *get_open_deferred_message(uint16 mid)
{
struct pending_message_list *pml;
- if (!lp_defer_sharing_violations()) {
- return NULL;
- }
-
- for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ for (pml = deferred_open_queue; pml; pml = pml->next) {
if (SVAL(pml->buf.data,smb_mid) == mid) {
return pml;
}
@@ -245,57 +199,216 @@ struct pending_message_list *get_open_deferred_message(uint16 mid)
}
/****************************************************************************
- Function to push a sharing violation open smb message onto a linked list of local smb messages ready
- for processing. We must use current_inbuf here not Inbuf in case we're in a chained message set.
+ Function to push a deferred open smb message onto a linked list of local smb
+ messages ready for processing.
+****************************************************************************/
+
+BOOL push_deferred_smb_message(uint16 mid,
+ struct timeval request_time,
+ struct timeval timeout,
+ char *private_data, size_t priv_len)
+{
+ struct timeval end_time;
+
+ end_time = timeval_sum(&request_time, &timeout);
+
+ DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u "
+ "timeout time [%u.%06u]\n",
+ (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid,
+ (unsigned int)end_time.tv_sec,
+ (unsigned int)end_time.tv_usec));
+
+ return push_queued_message(current_inbuf, smb_len(current_inbuf)+4,
+ request_time, end_time,
+ private_data, priv_len);
+}
+
+static struct timed_event *timed_events;
+
+struct timed_event {
+ struct timed_event *next, *prev;
+ struct timeval when;
+ const char *event_name;
+ void (*handler)(struct timed_event *te,
+ const struct timeval *now,
+ void *private_data);
+ void *private_data;
+};
+
+static int timed_event_destructor(void *p)
+{
+ struct timed_event *te = talloc_get_type_abort(p, struct timed_event);
+ DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
+ te->event_name));
+ DLIST_REMOVE(timed_events, te);
+ return 0;
+}
+
+/****************************************************************************
+ Schedule a function for future calling, cancel with talloc_free().
+ It's the responsibility of the handler to call talloc_free() on the event
+ handed to it.
****************************************************************************/
-BOOL push_sharing_violation_open_smb_message(struct timeval *ptv, char *private_data, size_t priv_len)
+struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx,
+ struct timeval when,
+ const char *event_name,
+ void (*handler)(struct timed_event *te,
+ const struct timeval *now,
+ void *private_data),
+ void *private_data)
{
- uint16 mid = SVAL(current_inbuf,smb_mid);
- struct timeval tv;
- SMB_BIG_INT tdif;
+ struct timed_event *te, *last_te, *cur_te;
- if (!lp_defer_sharing_violations()) {
- return True;
+ te = TALLOC_P(mem_ctx, struct timed_event);
+ if (te == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
}
- tv = *ptv;
- tdif = tv.tv_sec;
- tdif *= 1000000;
- tdif += tv.tv_usec;
+ te->when = when;
+ te->event_name = event_name;
+ te->handler = handler;
+ te->private_data = private_data;
+
+ /* keep the list ordered */
+ last_te = NULL;
+ for (cur_te = timed_events; cur_te; cur_te = cur_te->next) {
+ /* if the new event comes before the current one break */
+ if (!timeval_is_zero(&cur_te->when) &&
+ timeval_compare(&te->when, &cur_te->when) < 0) {
+ break;
+ }
+ last_te = cur_te;
+ }
- /* Add on the timeout. */
- tdif += SHARING_VIOLATION_USEC_WAIT;
-
- tv.tv_sec = tdif / 1000000;
- tv.tv_usec = tdif % 1000000;
-
- DEBUG(10,("push_sharing_violation_open_smb_message: pushing message len %u mid %u\
- timeout time [%u.%06u]\n", (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid,
- (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec));
+ DLIST_ADD_AFTER(timed_events, te, last_te);
+ talloc_set_destructor(te, timed_event_destructor);
- return push_queued_message(SHARE_VIOLATION_QUEUE, current_inbuf,
- smb_len(current_inbuf)+4, &tv, private_data, priv_len);
+ DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
+ (unsigned long)te));
+ return te;
}
+static void run_events(void)
+{
+ struct timeval now;
+
+ if (timed_events == NULL) {
+ /* No syscall if there are no events */
+ DEBUG(10, ("run_events: No events\n"));
+ return;
+ }
+
+ GetTimeOfDay(&now);
+
+ if (timeval_compare(&now, &timed_events->when) < 0) {
+ /* Nothing to do yet */
+ DEBUG(10, ("run_events: Nothing to do\n"));
+ return;
+ }
+
+ DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name,
+ (unsigned long)timed_events));
+
+ timed_events->handler(timed_events, &now, timed_events->private_data);
+ return;
+}
+
+struct timeval timed_events_timeout(void)
+{
+ struct timeval now, timeout;
+
+ if (timed_events == NULL) {
+ return timeval_set(SMBD_SELECT_TIMEOUT, 0);
+ }
+
+ now = timeval_current();
+ timeout = timeval_until(&now, &timed_events->when);
+
+ DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)timeout.tv_sec,
+ (int)timeout.tv_usec));
+
+ return timeout;
+}
+
+struct idle_event {
+ struct timed_event *te;
+ struct timeval interval;
+ BOOL (*handler)(const struct timeval *now, void *private_data);
+ void *private_data;
+};
+
+static void idle_event_handler(struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct idle_event *event =
+ talloc_get_type_abort(private_data, struct idle_event);
+
+ talloc_free(event->te);
+
+ if (!event->handler(now, event->private_data)) {
+ /* Don't repeat, delete ourselves */
+ talloc_free(event);
+ return;
+ }
+
+ event->te = add_timed_event(event, timeval_sum(now, &event->interval),
+ "idle_event_handler",
+ idle_event_handler, event);
+
+ /* We can't do much but fail here. */
+ SMB_ASSERT(event->te != NULL);
+}
+
+struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx,
+ struct timeval interval,
+ BOOL (*handler)(const struct timeval *now,
+ void *private_data),
+ void *private_data)
+{
+ struct idle_event *result;
+ struct timeval now = timeval_current();
+
+ result = TALLOC_P(mem_ctx, struct idle_event);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
+ }
+
+ result->interval = interval;
+ result->handler = handler;
+ result->private_data = private_data;
+
+ result->te = add_timed_event(result, timeval_sum(&now, &interval),
+ "idle_event_handler",
+ idle_event_handler, result);
+ if (result->te == NULL) {
+ DEBUG(0, ("add_timed_event failed\n"));
+ talloc_free(result);
+ return NULL;
+ }
+
+ return result;
+}
+
/****************************************************************************
- Do all async processing in here. This includes UDB oplock messages, kernel
- oplock messages, change notify events etc.
+ Do all async processing in here. This includes kernel oplock messages, change
+ notify events etc.
****************************************************************************/
-static void async_processing(char *buffer, int buffer_len)
+static void async_processing(void)
{
DEBUG(10,("async_processing: Doing async processing.\n"));
process_aio_queue();
- /* check for oplock messages (both UDP and kernel) */
- if (receive_local_message(buffer, buffer_len, 1)) {
- process_local_message(buffer, buffer_len);
- }
+ process_kernel_oplocks();
- /* Do the aio check again after receive_local_message as it does a select
- and may have eaten our signal. */
+ /* Do the aio check again after receive_local_message as it does a
+ select and may have eaten our signal. */
+ /* Is this till true? -- vl */
process_aio_queue();
if (got_sig_term) {
@@ -339,17 +452,17 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
{
fd_set fds;
int selrtn;
- struct timeval to;
- struct timeval *pto;
+ struct timeval to = timeval_set(SMBD_SELECT_TIMEOUT, 0);
int maxfd;
smb_read_error = 0;
again:
- to.tv_sec = timeout / 1000;
- to.tv_usec = (timeout % 1000) * 1000;
- pto = timeout > 0 ? &to : NULL;
+ if (timeout >= 0) {
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+ }
/*
* Note that this call must be before processing any SMB
@@ -359,37 +472,21 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
message_dispatch();
/*
- * Check to see if we already have a message on the smb queue.
- * If so - copy and return it.
- */
- if(smb_oplock_queue != NULL) {
- struct pending_message_list *msg = smb_oplock_queue;
- memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
-
- /* Free the message we just copied. */
- DLIST_REMOVE(smb_oplock_queue, msg);
- free_queued_message(msg);
-
- DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
- return True;
- }
-
- /*
* Check to see if we already have a message on the deferred open queue
* and it's time to schedule.
*/
- if(smb_sharing_violation_queue != NULL) {
+ if(deferred_open_queue != NULL) {
BOOL pop_message = False;
- struct pending_message_list *msg = smb_sharing_violation_queue;
+ struct pending_message_list *msg = deferred_open_queue;
- if (msg->msg_time.tv_sec == 0 && msg->msg_time.tv_usec == 0) {
+ if (timeval_is_zero(&msg->end_time)) {
pop_message = True;
} else {
struct timeval tv;
SMB_BIG_INT tdif;
GetTimeOfDay(&tv);
- tdif = usec_time_diff(&msg->msg_time, &tv);
+ tdif = usec_time_diff(&msg->end_time, &tv);
if (tdif <= 0) {
/* Timed out. Schedule...*/
pop_message = True;
@@ -398,9 +495,8 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
/* Make a more accurate select timeout. */
to.tv_sec = tdif / 1000000;
to.tv_usec = tdif % 1000000;
- pto = &to;
DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
- (unsigned int)pto->tv_sec, (unsigned int)pto->tv_usec ));
+ (unsigned int)to.tv_sec, (unsigned int)to.tv_usec ));
}
}
@@ -431,7 +527,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
if (oplock_message_waiting(&fds)) {
DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
- async_processing(buffer, buffer_len);
+ async_processing();
/*
* 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
@@ -439,18 +535,26 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
*/
goto again;
}
+
+ {
+ struct timeval tmp = timed_events_timeout();
+ to = timeval_min(&to, &tmp);
+ if (timeval_is_zero(&to)) {
+ return True;
+ }
+ }
FD_SET(smbd_server_fd(),&fds);
maxfd = setup_oplock_select_set(&fds);
- selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,pto);
+ selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,&to);
/* 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);
+ async_processing();
/*
* 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
@@ -479,7 +583,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
*/
if (oplock_message_waiting(&fds)) {
- async_processing(buffer, buffer_len);
+ async_processing();
/*
* 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
@@ -518,8 +622,6 @@ BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
void respond_to_all_remaining_local_messages(void)
{
- char buffer[1024];
-
/*
* Assert we have no exclusive open oplocks.
*/
@@ -530,15 +632,7 @@ void respond_to_all_remaining_local_messages(void)
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));
- }
+ process_kernel_oplocks();
return;
}
@@ -556,8 +650,7 @@ force write permissions on print services.
#define TIME_INIT (1<<2)
#define CAN_IPC (1<<3)
#define AS_GUEST (1<<5)
-#define QUEUE_IN_OPLOCK (1<<6)
-#define DO_CHDIR (1<<7)
+#define DO_CHDIR (1<<6)
/*
define a list of possible SMB messages and their corresponding
@@ -572,19 +665,19 @@ static const struct smb_message_struct {
/* 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 },
+/* 0x02 */ { "SMBopen",reply_open,AS_USER },
/* 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},
+/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
+/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
/* 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 },
+/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
/* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
@@ -611,11 +704,11 @@ static const struct smb_message_struct {
/* 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 },
+/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
+/* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
/* 0x2b */ { "SMBecho",reply_echo,0},
/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
-/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
/* 0x30 */ { NULL, NULL, 0 },
@@ -730,12 +823,12 @@ static const struct smb_message_struct {
/* 0x9d */ { NULL, NULL, 0 },
/* 0x9e */ { NULL, NULL, 0 },
/* 0x9f */ { NULL, NULL, 0 },
-/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
+/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
/* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
-/* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+/* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
/* 0xa3 */ { NULL, NULL, 0 },
/* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
-/* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+/* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER | NEED_WRITE },
/* 0xa6 */ { NULL, NULL, 0 },
/* 0xa7 */ { NULL, NULL, 0 },
/* 0xa8 */ { NULL, NULL, 0 },
@@ -762,7 +855,7 @@ static const struct smb_message_struct {
/* 0xbd */ { NULL, NULL, 0 },
/* 0xbe */ { NULL, NULL, 0 },
/* 0xbf */ { NULL, NULL, 0 },
-/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
+/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER},
/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
@@ -871,7 +964,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
pid = sys_getpid();
errno = 0;
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
last_message = type;
@@ -900,19 +993,6 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n",smb_fn_name(type),(int)pid,(unsigned long)conn));
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);
@@ -1289,6 +1369,7 @@ static int setup_select_timeout(void)
select_timeout *= 1000;
t = change_notify_timeout();
+ DEBUG(10, ("change_notify_timeout: %d\n", t));
if (t != -1)
select_timeout = MIN(select_timeout, t*1000);
@@ -1302,7 +1383,7 @@ static int setup_select_timeout(void)
Check if services need reloading.
****************************************************************************/
-void check_reload(int t)
+void check_reload(time_t t)
{
static pid_t mypid = 0;
static time_t last_smb_conf_reload_time = 0;
@@ -1644,6 +1725,8 @@ void smbd_process(void)
num_smbs = 0; /* Reset smb counter. */
}
+ run_events();
+
#if defined(DEVELOPER)
clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
#endif
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 5572f47e42..ba22a56cfb 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -30,7 +30,6 @@
extern enum protocol_types Protocol;
extern int max_send;
extern int max_recv;
-extern int global_oplock_break;
unsigned int smb_echo_count = 0;
extern uint32 global_client_caps;
@@ -1779,7 +1778,7 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
}
/* We need a better way to return NT status codes from open... */
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
fsp = open_file_ntcreate(conn, fname, pst,
DELETE_ACCESS,
@@ -1791,12 +1790,12 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
NULL);
if (!fsp) {
- NTSTATUS ret;
- if (get_saved_error_triple(NULL, NULL, &ret)) {
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ NTSTATUS ret = get_saved_ntstatus();
+ if (!NT_STATUS_IS_OK(ret)) {
+ set_saved_ntstatus(NT_STATUS_OK);
return ret;
}
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
return NT_STATUS_ACCESS_DENIED;
}
close_file(fsp,False);
@@ -1860,7 +1859,7 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b
don't do it here as we'll get it wrong. */
/* We need a better way to return NT status codes from open... */
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
fsp = open_file_ntcreate(conn, fname, &sbuf,
DELETE_ACCESS,
@@ -1872,12 +1871,12 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b
NULL);
if (!fsp) {
- NTSTATUS ret;
- if (get_saved_error_triple(NULL, NULL, &ret)) {
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ NTSTATUS ret = get_saved_ntstatus();
+ if (!NT_STATUS_IS_OK(ret)) {
+ set_saved_ntstatus(NT_STATUS_OK);
return ret;
}
- set_saved_error_triple(0, 0, NT_STATUS_OK);
+ set_saved_ntstatus(NT_STATUS_OK);
return NT_STATUS_ACCESS_DENIED;
}
close_file(fsp,False);
@@ -2209,15 +2208,6 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
* 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) {
@@ -2298,8 +2288,8 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
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 ) );
+ DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%lu min=%lu nread=%lu\n", fsp->fnum, (double)startpos,
+ (unsigned long)maxcount, (unsigned long)mincount, (unsigned long)nread ) );
send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf, out_buffsize);
@@ -3744,7 +3734,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if( is_ntfs_stream_name(directory)) {
DEBUG(5,("reply_mkdir: failing create on filename %s with colon in name\n", directory));
END_PROFILE(SMBmkdir);
- return ERROR_FORCE_DOS(ERRDOS, ERRinvalidname);
+ return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY);
}
status = mkdir_internal(conn, directory,bad_path);
@@ -5084,7 +5074,8 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma
Reply to a lockingX request.
****************************************************************************/
-int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+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);
@@ -5096,7 +5087,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
int32 lock_timeout = IVAL(inbuf,smb_vwv4);
int i;
char *data;
- BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+ BOOL large_file_format =
+ (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
BOOL err;
BOOL my_lock_ctx = False;
NTSTATUS status;
@@ -5125,19 +5117,25 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
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 ));
+ BOOL result;
+
+ 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.
+ * 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 (fsp->oplock_type == 0) {
+ DEBUG(0,("reply_lockingX: Error : oplock break from "
+ "client for fnum = %d (oplock=%d) and no "
+ "oplock granted on this file (%s).\n",
+ fsp->fnum, fsp->oplock_type, 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;
@@ -5147,17 +5145,30 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
}
}
- if (remove_oplock(fsp, break_to_none) == False) {
- DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
- fsp->fsp_name ));
+ if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
+ (break_to_none)) {
+ result = remove_oplock(fsp);
+ } else {
+ result = downgrade_oplock(fsp);
}
- /* if this is a pure oplock break request then don't send a reply */
+ if (!result) {
+ DEBUG(0, ("reply_lockingX: error in removing "
+ "oplock on file %s\n", fsp->fsp_name));
+ /* Hmmm. Is this panic justified? */
+ smb_panic("internal tdb error");
+ }
+
+ reply_to_oplock_break_requests(fsp);
+
+ /* 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",
+ 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;
@@ -5186,8 +5197,9 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
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 ));
+ 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)) {
@@ -5219,27 +5231,34 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
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 ));
+ 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);
+ ((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.
+ * 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)) {
+ 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)) {
+ if(push_blocking_lock_request(inbuf, length,
+ lock_timeout, i,
+ lock_pid, offset,
+ count)) {
END_PROFILE(SMBlockingX);
return -1;
}
@@ -5259,10 +5278,12 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
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);
+ offset = get_lock_offset( data, i, large_file_format,
+ &err);
/*
- * There is no error code marked "stupid client bug".... :-).
+ * There is no error code marked "stupid client
+ * bug".... :-).
*/
if(err) {
END_PROFILE(SMBlockingX);
@@ -5277,8 +5298,8 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
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 ) );
+ 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);
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 1ff03174fe..8310b408d0 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -96,7 +96,7 @@ static void killkids(void)
somewhere else.
****************************************************************************/
-static void msg_sam_sync(int UNUSED(msg_type), pid_t UNUSED(pid),
+static void msg_sam_sync(int UNUSED(msg_type), struct process_id UNUSED(pid),
void *UNUSED(buf), size_t UNUSED(len))
{
DEBUG(10, ("** sam sync message received, ignoring\n"));
@@ -107,7 +107,8 @@ static void msg_sam_sync(int UNUSED(msg_type), pid_t UNUSED(pid),
somewhere else.
****************************************************************************/
-static void msg_sam_repl(int msg_type, pid_t pid, void *buf, size_t len)
+static void msg_sam_repl(int msg_type, struct process_id pid,
+ void *buf, size_t len)
{
uint32 low_serial;
@@ -140,7 +141,8 @@ static BOOL open_sockets_inetd(void)
return True;
}
-static void msg_exit_server(int msg_type, pid_t src, void *buf, size_t len)
+static void msg_exit_server(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
exit_server("Got a SHUTDOWN message");
}
@@ -621,9 +623,6 @@ void exit_server(const char *reason)
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,"");
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index bf7287aab9..fc2d8b4abb 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -139,6 +139,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
int length, int bufsize,
DATA_BLOB *secblob)
{
+ TALLOC_CTX *mem_ctx;
DATA_BLOB ticket;
char *client, *p, *domain;
fstring netbios_domain_name;
@@ -146,7 +147,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
fstring user;
int sess_vuid;
NTSTATUS ret;
- DATA_BLOB auth_data;
+ PAC_DATA *pac_data;
DATA_BLOB ap_rep, ap_rep_wrapped, response;
auth_serversupplied_info *server_info = NULL;
DATA_BLOB session_key = data_blob(NULL, 0);
@@ -154,18 +155,24 @@ static int reply_spnego_kerberos(connection_struct *conn,
DATA_BLOB nullblob = data_blob(NULL, 0);
fstring real_username;
BOOL map_domainuser_to_guest = False;
+ PAC_LOGON_INFO *logon_info = NULL;
+ int i;
ZERO_STRUCT(ticket);
- ZERO_STRUCT(auth_data);
+ ZERO_STRUCT(pac_data);
ZERO_STRUCT(ap_rep);
ZERO_STRUCT(ap_rep_wrapped);
ZERO_STRUCT(response);
+ mem_ctx = talloc_init("reply_spnego_kerberos");
+ if (mem_ctx == NULL)
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+
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);
+ ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);
data_blob_free(&ticket);
@@ -174,7 +181,18 @@ static int reply_spnego_kerberos(connection_struct *conn,
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
- data_blob_free(&auth_data);
+ if (pac_data) {
+
+ /* get the logon_info */
+ for (i=0; i < pac_data->num_buffers; i++) {
+
+ if (pac_data->pac_buffer[i].type != PAC_TYPE_LOGON_INFO)
+ continue;
+
+ logon_info = pac_data->pac_buffer[i].ctr->pac.logon_info;
+ break;
+ }
+ }
DEBUG(3,("Ticket name is [%s]\n", client));
@@ -203,7 +221,14 @@ static int reply_spnego_kerberos(connection_struct *conn,
domain = p+1;
- {
+ if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
+
+ unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
+ domain = netbios_domain_name;
+ DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
+
+ } else {
+
/* 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
@@ -231,7 +256,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
wb_response.data.domain_info.name);
domain = netbios_domain_name;
- DEBUG(10, ("Mapped to [%s]\n", domain));
+ DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
} else {
DEBUG(3, ("Could not find short name -- winbind "
"not running?\n"));
@@ -274,8 +299,21 @@ static int reply_spnego_kerberos(connection_struct *conn,
reload_services(True);
if ( map_domainuser_to_guest ) {
make_server_info_guest(&server_info);
+ } else if (logon_info) {
+ ret = make_server_info_pac(&server_info, real_username, pw, logon_info);
+
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(1,("make_server_info_pac failed!\n"));
+ SAFE_FREE(client);
+ data_blob_free(&ap_rep);
+ data_blob_free(&session_key);
+ passwd_free(&pw);
+ return ERROR_NT(ret);
+ }
+
} else {
ret = make_server_info_pw(&server_info, real_username, pw);
+
if ( !NT_STATUS_IS_OK(ret) ) {
DEBUG(1,("make_server_info_from_pw failed!\n"));
SAFE_FREE(client);
@@ -284,15 +322,17 @@ static int reply_spnego_kerberos(connection_struct *conn,
passwd_free(&pw);
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);
+ }
}
- passwd_free(&pw);
- /* 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);
- }
+ passwd_free(&pw);
/* register_vuid keeps the server info */
/* register_vuid takes ownership of session_key, no need to free after this.
@@ -339,6 +379,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
data_blob_free(&ap_rep);
data_blob_free(&ap_rep_wrapped);
data_blob_free(&response);
+ talloc_destroy(mem_ctx);
return -1; /* already replied */
}
@@ -348,6 +389,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
Send a session setup reply, wrapped in SPNEGO.
Get vuid and check first.
End the NTLMSSP exchange context if we are OK/complete fail
+ This should be split into two functions, one to handle each
+ leg of the NTLM auth steps.
***************************************************************************/
static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
@@ -422,6 +465,7 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
and the other end, that we are not finished yet. */
if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /* NB. This is *NOT* an error case. JRA */
auth_ntlmssp_end(auth_ntlmssp_state);
/* Kill the intermediate vuid */
invalidate_vuid(vuid);
@@ -660,7 +704,7 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
return ret;
}
- if (strncmp(blob1.data, "NTLMSSP", 7) == 0) {
+ if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
DATA_BLOB chal;
NTSTATUS nt_status;
if (!vuser->auth_ntlmssp_state) {
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 38363bf66a..f0b7812a1e 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -27,7 +27,6 @@
extern int max_send;
extern enum protocol_types Protocol;
extern int smb_read_error;
-extern int global_oplock_break;
extern uint32 global_client_caps;
extern struct current_user current_user;
@@ -2789,7 +2788,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
delete_pending =
get_delete_on_close_flag(sbuf.st_dev,
- sbuf.st_ino);
+ sbuf.st_ino,
+ fname);
} else {
/*
* Original code - this is an open file.
@@ -2804,7 +2804,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
pos = fsp->fh->position_information;
delete_pending =
get_delete_on_close_flag(sbuf.st_dev,
- sbuf.st_ino);
+ sbuf.st_ino,
+ fname);
access_mask = fsp->access_mask;
}
} else {
@@ -2847,7 +2848,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
}
delete_pending = get_delete_on_close_flag(sbuf.st_dev,
- sbuf.st_ino);
+ sbuf.st_ino,
+ fname);
if (delete_pending) {
return ERROR_NT(NT_STATUS_DELETE_PENDING);
}
@@ -3455,91 +3457,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
/****************************************************************************
- 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 can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close,
- uint32 dosmode)
-{
- if (!delete_on_close) {
- return NT_STATUS_OK;
- }
-
- /*
- * Only allow delete on close for writable files.
- */
-
- if ((dosmode & aRONLY) &&
- !lp_delete_readonly(SNUM(fsp->conn))) {
- DEBUG(10,("can_set_delete_on_close: file %s delete on close "
- "flag set but file attribute is readonly.\n",
- fsp->fsp_name ));
- return NT_STATUS_CANNOT_DELETE;
- }
-
- /*
- * Only allow delete on close for writable shares.
- */
-
- if (!CAN_WRITE(fsp->conn)) {
- DEBUG(10,("can_set_delete_on_close: 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 (!(fsp->access_mask & DELETE_ACCESS)) {
- DEBUG(10,("can_set_delete_on_close: file %s delete on "
- "close flag set but delete access denied.\n",
- fsp->fsp_name ));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- 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(files_struct *fsp, BOOL delete_on_close)
-{
- DEBUG(10,("set_delete_on_close: %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: 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;
-}
-
-/****************************************************************************
Set a hard link (called by UNIX extensions and by NT rename with HARD link
code.
****************************************************************************/
@@ -3912,16 +3829,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
if (fd == -1) {
files_struct *new_fsp = NULL;
- 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_ntcreate(conn, fname, &sbuf,
FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,
@@ -4003,9 +3910,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
}
/* The set is across all open files on this dev/inode pair. */
- status =set_delete_on_close(fsp, delete_on_close);
- if (!NT_STATUS_IS_OK(status)) {
- return ERROR_NT(status);
+ if (!set_delete_on_close(fsp, delete_on_close)) {
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
}
SSVAL(params,0,0);
@@ -4456,16 +4362,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
if (fd == -1) {
files_struct *new_fsp = NULL;
- 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_ntcreate(conn, fname, &sbuf,
FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,
@@ -4859,18 +4755,6 @@ int reply_trans2(connection_struct *conn,
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);